Add basic authentication

master
esensar 2017-05-29 09:27:53 +02:00
parent f14d1cbe55
commit 5c3a592a55
10 changed files with 273 additions and 47 deletions

View File

@ -38,6 +38,7 @@ dependencies {
compile('mysql:mysql-connector-java')
compile('org.hibernate:hibernate-validator')
compile('org.springframework.cloud:spring-cloud-starter-eureka')
compile('io.jsonwebtoken:jjwt:0.7.0')
compile project(':common')
testCompile('org.springframework.cloud:spring-cloud-starter-eureka-server')

View File

@ -11,7 +11,7 @@ import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class UsersConfig {
@Bean
public PasswordEncoder providePasswordEncoder(){
public static PasswordEncoder providePasswordEncoder(){
return new BCryptPasswordEncoder();
}
}

View File

@ -19,6 +19,13 @@ public class UserRole {
private String roleName;
public UserRole() {
}
public UserRole(String roleName) {
this.roleName = roleName;
}
public long getId() {
return id;
}
@ -34,4 +41,19 @@ public class UserRole {
public void setRoleName(String roleName) {
this.roleName = roleName;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
UserRole userRole = (UserRole) o;
return roleName != null ? roleName.equals(userRole.roleName) : userRole.roleName == null;
}
@Override
public int hashCode() {
return roleName != null ? roleName.hashCode() : 0;
}
}

View File

@ -0,0 +1,36 @@
package ba.steleks.security;/**
* Created by ensar on 28/05/17.
*/
public class AccountCredentials {
private String username;
private String password;
private String role;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
}

View File

@ -0,0 +1,26 @@
package ba.steleks.security;/**
* Created by ensar on 28/05/17.
*/
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.GenericFilterBean;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
public class JWTAuthenticationFilter extends GenericFilterBean {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws IOException, ServletException {
Authentication authentication = TokenAuthenticationService.getAuthentication((HttpServletRequest) request);
SecurityContextHolder.getContext().setAuthentication(authentication);
filterChain.doFilter(request, response);
}
}

View File

@ -0,0 +1,42 @@
package ba.steleks.security;/**
* Created by ensar on 28/05/17.
*/
import ba.steleks.model.UserRole;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
import java.util.Set;
public class JWTLoginFilter extends AbstractAuthenticationProcessingFilter {
public JWTLoginFilter(String defaultFilterProcessesUrl, AuthenticationManager authenticationManager) {
super(defaultFilterProcessesUrl);
setAuthenticationManager(authenticationManager);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
AccountCredentials creds = new ObjectMapper().readValue(request.getInputStream(), AccountCredentials.class);
return getAuthenticationManager().authenticate(new UsernamePasswordAuthenticationToken(creds.getUsername(),
creds.getPassword(), Collections.emptyList()));
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
super.successfulAuthentication(request, response, chain, authResult);
Set<UserRole> userRoles = UserRoleFactory.fromGrantedAuthorities(authResult.getAuthorities());
TokenAuthenticationService.addAuthenticationHeader(response, authResult.getName(), userRoles);
}
}

View File

@ -6,15 +6,12 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableWebSecurity
@ -22,23 +19,26 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public AuthenticationProvider provideAuthenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(new SteleksUsersDetailsService());
return authenticationProvider;
public UserDetailsService provideUserDetailsService() {
return new SteleksUsersDetailsService();
}
@Autowired
private AuthenticationProvider authProvider;
private UserDetailsService userDetailsService;
@Override
protected void configure(
AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authProvider);
auth.userDetailsService(userDetailsService);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated();
http.csrf().disable().authorizeRequests()
.anyRequest().authenticated()
.and()
.addFilterBefore(new JWTLoginFilter("/accesstoken", authenticationManager()),
UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new JWTAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
}

View File

@ -3,19 +3,22 @@ package ba.steleks.security;/**
*/
import ba.steleks.model.User;
import ba.steleks.model.UserRole;
import ba.steleks.repository.UsersJpaRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.logging.Logger;
import java.util.stream.Collectors;
public class SteleksUsersDetailsService implements UserDetailsService {
private static final Logger logger =
Logger.getLogger(SteleksUsersDetailsService.class.getName());
@Autowired
private UsersJpaRepository usersJpaRepository;
@ -23,42 +26,17 @@ public class SteleksUsersDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = usersJpaRepository.findByUsername(username);
UserDetails userDetails = new UserDetails() {
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}
@Override
public String getPassword() {
return null;
}
if(user == null) {
throw new UsernameNotFoundException(username);
}
@Override
public String getUsername() {
return null;
}
List<GrantedAuthority> authorities =
UserRoleFactory.toGrantedAuthorities(user.getUserRoles());
@Override
public boolean isAccountNonExpired() {
return false;
}
@Override
public boolean isAccountNonLocked() {
return false;
}
@Override
public boolean isCredentialsNonExpired() {
return false;
}
@Override
public boolean isEnabled() {
return false;
}
};
return userDetails;
return new org.springframework.security.core.userdetails.User(user.getUsername(),
user.getPasswordHash(),
authorities);
}
}

View File

@ -0,0 +1,73 @@
package ba.steleks.security;
import ba.steleks.model.UserRole;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.sql.Date;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
/**
* Created by ensar on 28/05/17.
*/
class TokenAuthenticationService {
static final long EXPIRATION_TIME = 864_000_000; // 10 days
static final String SECRET = "ASteleksSecret";
static final String TOKEN_PREFIX = "Bearer";
static final String HEADER_STRING = "Authorization";
static final String ROLES = "roles";
static void addAuthenticationHeader(HttpServletResponse res, String username, Set<UserRole> userRoleSet) {
String JWT = Jwts.builder()
.setSubject(username)
.claim(ROLES, UserRoleFactory.toString(userRoleSet))
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
.signWith(SignatureAlgorithm.HS512, SECRET).compact();
res.addHeader(HEADER_STRING, TOKEN_PREFIX + " " + JWT);
}
static Authentication getAuthentication(HttpServletRequest request) {
String token = request.getHeader(HEADER_STRING);
if (token != null) {
// parse the token.
Claims claims = Jwts.parser()
.setSigningKey(SECRET)
.parseClaimsJws(token.replaceFirst(TOKEN_PREFIX, ""))
.getBody();
String userName = claims.getSubject();
Set<UserRole> userRoles = UserRoleFactory.fromString(claims.get(ROLES, String.class));
if (userName != null) {
boolean access = false;
UserRole theUserRole = new UserRole("theUser");
if(userRoles.contains(theUserRole)) {
access = true;
}
if (access) {
return new UsernamePasswordAuthenticationToken(userName,
null,
UserRoleFactory.toGrantedAuthorities(userRoles));
}
else {
return new UsernamePasswordAuthenticationToken(userName,
null);
}
}
}
return null;
}
}

View File

@ -0,0 +1,48 @@
package ba.steleks.security;/**
* Created by ensar on 28/05/17.
*/
import ba.steleks.model.UserRole;
import com.google.common.collect.Lists;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import java.util.*;
import java.util.stream.Collectors;
public class UserRoleFactory {
public static String toString(Collection<UserRole> userRoleSet) {
// Transform to list
List<UserRole> userRoleList = Lists.newArrayList(userRoleSet);
// Sort by role name - to make different sets look the same in the end
userRoleList.sort(Comparator.comparing(UserRole::getRoleName));
// Transform to string
return userRoleList.stream().map(UserRole::getRoleName).collect(Collectors.joining(","));
}
public static Set<UserRole> fromString(String userRoleString) {
Set<UserRole> userRoles = new HashSet<>();
Arrays.stream(userRoleString.split(",")).map(UserRole::new).forEach(userRoles::add);
return userRoles;
}
public static List<GrantedAuthority> toGrantedAuthorities(Collection<UserRole> userRoleSet) {
return userRoleSet
.stream()
// get role name
.map(UserRole::getRoleName)
// create authority
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
}
public static Set<UserRole> fromGrantedAuthorities(Collection<? extends GrantedAuthority> grantedAuthorities) {
return grantedAuthorities
.stream()
.map(GrantedAuthority::getAuthority)
.map(UserRole::new)
.collect(Collectors.toSet());
}
}