From 01065f8606810bc431fe96cb7ce5168c03336b1e Mon Sep 17 00:00:00 2001 From: Madison Date: Tue, 28 Mar 2017 15:22:10 -0700 Subject: [PATCH 01/19] Add security compatibility, temporary token generator; testing needed. --- pom.xml | 31 ++- .../revature/config/WebSecurityConfig.java | 92 +++++++++ .../revature/model/security/Authority.java | 62 ++++++ .../model/security/AuthorityName.java | 14 ++ .../com/revature/model/security/User.java | 158 ++++++++++++++++ .../security/JwtAuthenticationEntryPoint.java | 25 +++ .../security/JwtAuthenticationFilter.java | 64 +++++++ .../security/JwtAuthenticationRequest.java | 45 +++++ .../JwtAuthenticationSuccessHandler.java | 24 +++ .../com/revature/security/JwtTokenUtil.java | 176 ++++++++++++++++++ .../java/com/revature/security/JwtUser.java | 113 +++++++++++ .../com/revature/security/JwtUserFactory.java | 45 +++++ .../AuthenticationRestController.java | 79 ++++++++ .../controllers/UserRestController.java | 46 +++++ .../exceptions/JwtTokenMissingException.java | 19 ++ .../security/repository/UserRepository.java | 17 ++ .../service/JwtAuthenticationResponse.java | 27 +++ .../service/JwtUserDetailsServiceImpl.java | 37 ++++ src/main/resources/application.yml | 21 +++ 19 files changed, 1094 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/revature/config/WebSecurityConfig.java create mode 100644 src/main/java/com/revature/model/security/Authority.java create mode 100644 src/main/java/com/revature/model/security/AuthorityName.java create mode 100644 src/main/java/com/revature/model/security/User.java create mode 100644 src/main/java/com/revature/security/JwtAuthenticationEntryPoint.java create mode 100644 src/main/java/com/revature/security/JwtAuthenticationFilter.java create mode 100644 src/main/java/com/revature/security/JwtAuthenticationRequest.java create mode 100644 src/main/java/com/revature/security/JwtAuthenticationSuccessHandler.java create mode 100644 src/main/java/com/revature/security/JwtTokenUtil.java create mode 100644 src/main/java/com/revature/security/JwtUser.java create mode 100644 src/main/java/com/revature/security/JwtUserFactory.java create mode 100644 src/main/java/com/revature/security/controllers/AuthenticationRestController.java create mode 100644 src/main/java/com/revature/security/controllers/UserRestController.java create mode 100644 src/main/java/com/revature/security/exceptions/JwtTokenMissingException.java create mode 100644 src/main/java/com/revature/security/repository/UserRepository.java create mode 100644 src/main/java/com/revature/security/service/JwtAuthenticationResponse.java create mode 100644 src/main/java/com/revature/security/service/JwtUserDetailsServiceImpl.java create mode 100644 src/main/resources/application.yml diff --git a/pom.xml b/pom.xml index 2978103..2b2e740 100644 --- a/pom.xml +++ b/pom.xml @@ -113,7 +113,36 @@ spring-boot-devtools true - + + org.springframework.mobile + spring-mobile-device + 1.1.5.RELEASE + jar + + + org.springframework.security + spring-security-core + 4.2.1.RELEASE + jar + + + org.springframework.security + spring-security-web + 4.2.1.RELEASE + jar + + + io.jsonwebtoken + jjwt + 0.7.0 + jar + + + org.springframework.security + spring-security-config + 4.2.1.RELEASE + jar + diff --git a/src/main/java/com/revature/config/WebSecurityConfig.java b/src/main/java/com/revature/config/WebSecurityConfig.java new file mode 100644 index 0000000..b970f06 --- /dev/null +++ b/src/main/java/com/revature/config/WebSecurityConfig.java @@ -0,0 +1,92 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.config; + +import com.revature.security.JwtAuthenticationEntryPoint; +import com.revature.security.JwtAuthenticationFilter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +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.config.http.SessionCreationPolicy; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +/** + * + * @author FayeRedd + */ + +@SuppressWarnings("SpringJavaAutowiringInspection") +@Configuration +@EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true) +public class WebSecurityConfig extends WebSecurityConfigurerAdapter{ + + @Autowired + private JwtAuthenticationEntryPoint unauthorizedHandler; + + @Autowired + private UserDetailsService userDetailsService; + + @Autowired + public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception{ + authenticationManagerBuilder + .userDetailsService(this.userDetailsService) + .passwordEncoder(passwordEncoder()); + } + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Bean + public JwtAuthenticationFilter authenticationFilterBean() throws Exception { + return new JwtAuthenticationFilter(); + } + + @Override + protected void configure(HttpSecurity httpSecurity) throws Exception{ + httpSecurity + .csrf().disable() + + .exceptionHandling().authenticationEntryPoint(unauthorizedHandler) + + .and() + + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) + + .and() + + .authorizeRequests() + + .antMatchers( + HttpMethod.GET, + "/", + "/*.html", + "/favicon.ico", + "/**/*.html", + "/**/*.css", + "/**/*.js" + ).permitAll() + .antMatchers("/auth/**").permitAll() + .anyRequest().authenticated(); + + httpSecurity + .addFilterBefore(authenticationFilterBean(), UsernamePasswordAuthenticationFilter.class); + + httpSecurity.headers().cacheControl(); + + } +} diff --git a/src/main/java/com/revature/model/security/Authority.java b/src/main/java/com/revature/model/security/Authority.java new file mode 100644 index 0000000..0a8f825 --- /dev/null +++ b/src/main/java/com/revature/model/security/Authority.java @@ -0,0 +1,62 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.model.security; + +/** + * + * @author FayeRedd + */ +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import java.util.List; + +/* +This is a placeholder Entity for an "Authority" POJO. Feel free to modify/edit as needed +for compatibility with actual database Table +*/ + +@Entity +@Table(name = "AUTHORITY") +public class Authority { + + @Id + @Column(name = "ID") + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "authority_seq") + @SequenceGenerator(name = "authority_seq", sequenceName = "authority_seq", allocationSize = 1) + private Long id; + + @Column(name = "NAME", length = 50) + @NotNull + @Enumerated(EnumType.STRING) + private AuthorityName name; + + @ManyToMany(mappedBy = "authorities", fetch = FetchType.LAZY) + private List users; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public AuthorityName getName() { + return name; + } + + public void setName(AuthorityName name) { + this.name = name; + } + + public List getUsers() { + return users; + } + + public void setUsers(List users) { + this.users = users; + } +} \ No newline at end of file diff --git a/src/main/java/com/revature/model/security/AuthorityName.java b/src/main/java/com/revature/model/security/AuthorityName.java new file mode 100644 index 0000000..95d8929 --- /dev/null +++ b/src/main/java/com/revature/model/security/AuthorityName.java @@ -0,0 +1,14 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.model.security; + +/** + * + * @author FayeRedd + */ +public enum AuthorityName { + ROLE_USER, ROLE_ADMIN +} diff --git a/src/main/java/com/revature/model/security/User.java b/src/main/java/com/revature/model/security/User.java new file mode 100644 index 0000000..d1dc7f1 --- /dev/null +++ b/src/main/java/com/revature/model/security/User.java @@ -0,0 +1,158 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.model.security; + +/** + * + * @author FayeRedd + */ +import java.util.Date; +import java.util.List; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToMany; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +/* +This is a placeholder Entity for the User POJO. Feel free to modify/edit as needed +for compatibility with actual database Table +*/ + +@Entity +@Table(name = "USER") +public class User { + + @Id + @Column(name = "ID") + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_seq") + @SequenceGenerator(name = "user_seq", sequenceName = "user_seq", allocationSize = 1) + private Long id; + + @Column(name = "USERNAME", length = 50, unique = true) + @NotNull + @Size(min = 4, max = 50) + private String username; + + @Column(name = "PASSWORD", length = 100) + @NotNull + @Size(min = 4, max = 100) + private String password; + + @Column(name = "FIRSTNAME", length = 50) + @NotNull + @Size(min = 4, max = 50) + private String firstname; + + @Column(name = "LASTNAME", length = 50) + @NotNull + @Size(min = 4, max = 50) + private String lastname; + + @Column(name = "EMAIL", length = 50) + @NotNull + @Size(min = 4, max = 50) + private String email; + + @Column(name = "ENABLED") + @NotNull + private Boolean enabled; + + @Column(name = "LASTPASSWORDRESETDATE") + @Temporal(TemporalType.TIMESTAMP) + @NotNull + private Date lastPasswordResetDate; + + @ManyToMany(fetch = FetchType.EAGER) + @JoinTable( + name = "USER_AUTHORITY", + joinColumns = {@JoinColumn(name = "USER_ID", referencedColumnName = "ID")}, + inverseJoinColumns = {@JoinColumn(name = "AUTHORITY_ID", referencedColumnName = "ID")}) + private List authorities; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + 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 getFirstname() { + return firstname; + } + + public void setFirstname(String firstname) { + this.firstname = firstname; + } + + public String getLastname() { + return lastname; + } + + public void setLastname(String lastname) { + this.lastname = lastname; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public Boolean getEnabled() { + return enabled; + } + + public void setEnabled(Boolean enabled) { + this.enabled = enabled; + } + + public List getAuthorities() { + return authorities; + } + + public void setAuthorities(List authorities) { + this.authorities = authorities; + } + + public Date getLastPasswordResetDate() { + return lastPasswordResetDate; + } + + public void setLastPasswordResetDate(Date lastPasswordResetDate) { + this.lastPasswordResetDate = lastPasswordResetDate; + } +} diff --git a/src/main/java/com/revature/security/JwtAuthenticationEntryPoint.java b/src/main/java/com/revature/security/JwtAuthenticationEntryPoint.java new file mode 100644 index 0000000..bd1f293 --- /dev/null +++ b/src/main/java/com/revature/security/JwtAuthenticationEntryPoint.java @@ -0,0 +1,25 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security; + +import java.io.IOException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; + +/** + * + * @author FayeRedd + */ +public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint{ + + @Override + public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException { + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); + } + +} diff --git a/src/main/java/com/revature/security/JwtAuthenticationFilter.java b/src/main/java/com/revature/security/JwtAuthenticationFilter.java new file mode 100644 index 0000000..5c66344 --- /dev/null +++ b/src/main/java/com/revature/security/JwtAuthenticationFilter.java @@ -0,0 +1,64 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security; + +import java.io.IOException; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.web.filter.OncePerRequestFilter; + +/** + * + * @author FayeRedd + */ +public class JwtAuthenticationFilter extends OncePerRequestFilter { + + private final Log logger = LogFactory.getLog(this.getClass()); + + @Autowired + private UserDetailsService userDetailsService; + + @Autowired + private JwtTokenUtil jwtTokenUtil; + + @Value("Authorization") + private String tokenHeader; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { + String authToken = request.getHeader(this.tokenHeader); + + String username = jwtTokenUtil.getUsernameFromToken(authToken); + + logger.info("checking authentication for das user " + username); + + if(username != null && SecurityContextHolder.getContext().getAuthentication() == null){ + UserDetails userDetails = this.userDetailsService.loadUserByUsername(username); + + if(jwtTokenUtil.validateToken(authToken, userDetails)){ + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); + + authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + + logger.info("authenticated user " + username + ", setting security context"); + + SecurityContextHolder.getContext().setAuthentication(authentication); + } + } + chain.doFilter(request, response); + } +} diff --git a/src/main/java/com/revature/security/JwtAuthenticationRequest.java b/src/main/java/com/revature/security/JwtAuthenticationRequest.java new file mode 100644 index 0000000..c6555c9 --- /dev/null +++ b/src/main/java/com/revature/security/JwtAuthenticationRequest.java @@ -0,0 +1,45 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security; + +import java.io.Serializable; + +/** + * + * @author FayeRedd + */ +public class JwtAuthenticationRequest implements Serializable { + + private static final long serialVersionUID = -8445943548965154778L; + + private String username; + private String password; + + public JwtAuthenticationRequest() { + super(); + } + + public JwtAuthenticationRequest(String username, String password) { + this.setUsername(username); + this.setPassword(password); + } + + public String getUsername() { + return this.username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return this.password; + } + + public void setPassword(String password) { + this.password = password; + } +} diff --git a/src/main/java/com/revature/security/JwtAuthenticationSuccessHandler.java b/src/main/java/com/revature/security/JwtAuthenticationSuccessHandler.java new file mode 100644 index 0000000..a7ee1e2 --- /dev/null +++ b/src/main/java/com/revature/security/JwtAuthenticationSuccessHandler.java @@ -0,0 +1,24 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security; + +import java.io.IOException; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.springframework.security.core.Authentication; +import org.springframework.security.web.authentication.AuthenticationSuccessHandler; + +/** + * + * @author FayeRedd + */ +public class JwtAuthenticationSuccessHandler implements AuthenticationSuccessHandler{ + + @Override + public void onAuthenticationSuccess(HttpServletRequest hsr, HttpServletResponse hsr1, Authentication a) throws IOException, ServletException {} + +} diff --git a/src/main/java/com/revature/security/JwtTokenUtil.java b/src/main/java/com/revature/security/JwtTokenUtil.java new file mode 100644 index 0000000..64783a3 --- /dev/null +++ b/src/main/java/com/revature/security/JwtTokenUtil.java @@ -0,0 +1,176 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security; + +/** + * + * @author FayeRedd + */ +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.mobile.device.Device; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Component; + +import java.io.Serializable; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +@Component +public class JwtTokenUtil implements Serializable { + + private static final long serialVersionUID = -3301605591108950415L; + + static final String CLAIM_KEY_USERNAME = "sub"; + static final String CLAIM_KEY_AUDIENCE = "audience"; + static final String CLAIM_KEY_CREATED = "created"; + + private static final String AUDIENCE_UNKNOWN = "unknown"; + private static final String AUDIENCE_WEB = "web"; + private static final String AUDIENCE_MOBILE = "mobile"; + private static final String AUDIENCE_TABLET = "tablet"; + + @Value("${jwt.secret}") + private String secret; + + @Value("${jwt.expiration}") + private Long expiration; + + public String getUsernameFromToken(String token) { + String username; + try { + final Claims claims = getClaimsFromToken(token); + username = claims.getSubject(); + } catch (Exception e) { + username = null; + } + return username; + } + + public Date getCreatedDateFromToken(String token) { + Date created; + try { + final Claims claims = getClaimsFromToken(token); + created = new Date((Long) claims.get(CLAIM_KEY_CREATED)); + } catch (Exception e) { + created = null; + } + return created; + } + + public Date getExpirationDateFromToken(String token) { + Date expires; + try { + final Claims claims = getClaimsFromToken(token); + expires = claims.getExpiration(); + } catch (Exception e) { + expires = null; + } + return expires; + } + + public String getAudienceFromToken(String token) { + String audience; + try { + final Claims claims = getClaimsFromToken(token); + audience = (String) claims.get(CLAIM_KEY_AUDIENCE); + } catch (Exception e) { + audience = null; + } + return audience; + } + + private Claims getClaimsFromToken(String token) { + Claims claims; + try { + claims = Jwts.parser() + .setSigningKey(secret) + .parseClaimsJws(token) + .getBody(); + } catch (Exception e) { + claims = null; + } + return claims; + } + + private Date generateExpirationDate() { + return new Date(System.currentTimeMillis() + expiration * 1000); + } + + private Boolean isTokenExpired(String token) { + final Date expires = getExpirationDateFromToken(token); + return expires.before(new Date()); + } + + private Boolean isCreatedBeforeLastPasswordReset(Date created, Date lastPasswordReset) { + return (lastPasswordReset != null && created.before(lastPasswordReset)); + } + + private String generateAudience(Device device) { + String audience = AUDIENCE_UNKNOWN; + if (device.isNormal()) { + audience = AUDIENCE_WEB; + } else if (device.isTablet()) { + audience = AUDIENCE_TABLET; + } else if (device.isMobile()) { + audience = AUDIENCE_MOBILE; + } + return audience; + } + + private Boolean ignoreTokenExpiration(String token) { + String audience = getAudienceFromToken(token); + return (AUDIENCE_TABLET.equals(audience) || AUDIENCE_MOBILE.equals(audience)); + } + + public String generateToken(UserDetails userDetails, Device device) { + Map claims = new HashMap<>(); + claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername()); + claims.put(CLAIM_KEY_AUDIENCE, generateAudience(device)); + claims.put(CLAIM_KEY_CREATED, new Date()); + return generateToken(claims); + } + + String generateToken(Map claims) { + return Jwts.builder() + .setClaims(claims) + .setExpiration(generateExpirationDate()) + .signWith(SignatureAlgorithm.HS512, secret) + .compact(); + } + + public Boolean canTokenBeRefreshed(String token, Date lastPasswordReset) { + final Date created = getCreatedDateFromToken(token); + return !isCreatedBeforeLastPasswordReset(created, lastPasswordReset) + && (!isTokenExpired(token) || ignoreTokenExpiration(token)); + } + + public String refreshToken(String token) { + String refreshedToken; + try { + final Claims claims = getClaimsFromToken(token); + claims.put(CLAIM_KEY_CREATED, new Date()); + refreshedToken = generateToken(claims); + } catch (Exception e) { + refreshedToken = null; + } + return refreshedToken; + } + + public Boolean validateToken(String token, UserDetails userDetails) { + JwtUser user = (JwtUser) userDetails; + final String username = getUsernameFromToken(token); + final Date created = getCreatedDateFromToken(token); + //final Date expiration = getExpirationDateFromToken(token); + return ( + username.equals(user.getUsername()) + && !isTokenExpired(token) + && !isCreatedBeforeLastPasswordReset(created, user.getLastPasswordResetDate())); + } +} \ No newline at end of file diff --git a/src/main/java/com/revature/security/JwtUser.java b/src/main/java/com/revature/security/JwtUser.java new file mode 100644 index 0000000..6f15b77 --- /dev/null +++ b/src/main/java/com/revature/security/JwtUser.java @@ -0,0 +1,113 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security; + +/** + * + * @author FayeRedd + */ +import java.util.Collection; +import java.util.Date; + +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +public class JwtUser implements UserDetails { + + private final Long id; + private final String username; + private final String firstname; + private final String lastname; + private final String password; + private final String email; + private final Collection authorities; + private final boolean enabled; + private final Date lastPasswordResetDate; + + public JwtUser( + Long id, + String username, + String firstname, + String lastname, + String email, + String password, Collection authorities, + boolean enabled, + Date lastPasswordResetDate + ) { + this.id = id; + this.username = username; + this.firstname = firstname; + this.lastname = lastname; + this.email = email; + this.password = password; + this.authorities = authorities; + this.enabled = enabled; + this.lastPasswordResetDate = lastPasswordResetDate; + } + + @JsonIgnore + public Long getId() { + return id; + } + + @Override + public String getUsername() { + return username; + } + + @JsonIgnore + @Override + public boolean isAccountNonExpired() { + return true; + } + + @JsonIgnore + @Override + public boolean isAccountNonLocked() { + return true; + } + + @JsonIgnore + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + public String getFirstname() { + return firstname; + } + + public String getLastname() { + return lastname; + } + + public String getEmail() { + return email; + } + + @JsonIgnore + @Override + public String getPassword() { + return password; + } + + @Override + public Collection getAuthorities() { + return authorities; + } + + @Override + public boolean isEnabled() { + return enabled; + } + + @JsonIgnore + public Date getLastPasswordResetDate() { + return lastPasswordResetDate; + } +} diff --git a/src/main/java/com/revature/security/JwtUserFactory.java b/src/main/java/com/revature/security/JwtUserFactory.java new file mode 100644 index 0000000..4bdd5b4 --- /dev/null +++ b/src/main/java/com/revature/security/JwtUserFactory.java @@ -0,0 +1,45 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security; + +import com.revature.model.security.Authority; +import com.revature.model.security.User; +import java.util.List; +import java.util.stream.Collectors; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; + + + +/** + * + * @author FayeRedd + */ +public class JwtUserFactory { + + private JwtUserFactory(){} + + public static JwtUser create(User user){ + return new JwtUser( + user.getId(), + user.getUsername(), + user.getFirstname(), + user.getLastname(), + user.getEmail(), + user.getPassword(), + mapToGrantedAuthorities(user.getAuthorities()), + user.getEnabled(), + user.getLastPasswordResetDate() + ); + } + + private static List mapToGrantedAuthorities(List authorities) { + return authorities.stream() + .map(authority -> new SimpleGrantedAuthority(authority.getName().name())) + .collect(Collectors.toList()); + } + +} diff --git a/src/main/java/com/revature/security/controllers/AuthenticationRestController.java b/src/main/java/com/revature/security/controllers/AuthenticationRestController.java new file mode 100644 index 0000000..ba28b27 --- /dev/null +++ b/src/main/java/com/revature/security/controllers/AuthenticationRestController.java @@ -0,0 +1,79 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security.controllers; + +import com.revature.security.JwtAuthenticationRequest; +import com.revature.security.JwtTokenUtil; +import com.revature.security.JwtUser; +import com.revature.security.service.JwtAuthenticationResponse; +import javax.servlet.http.HttpServletRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.ResponseEntity; +import org.springframework.mobile.device.Device; +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.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.security.core.userdetails.UserDetails; + +/** + * + * @author FayeRedd + */ + +@RestController +public class AuthenticationRestController { + + @Value("${jwt.header}") + private String tokenHeader; + + @Autowired + private AuthenticationManager authMan; + + @Autowired + private JwtTokenUtil tokenUtil; + + @Autowired + private UserDetailsService userDetServ; + + @RequestMapping(value = "${jwt.route.authentication.path}", method = RequestMethod.POST) + public ResponseEntity createAuthenticationToken(@RequestBody JwtAuthenticationRequest authReq, Device dev) throws AuthenticationException{ + + final Authentication authentication = authMan.authenticate( + new UsernamePasswordAuthenticationToken( + authReq.getUsername(), + authReq.getPassword()) + ); + + SecurityContextHolder.getContext().setAuthentication(authentication); + + final UserDetails userDetails = userDetServ.loadUserByUsername(authReq.getUsername()); + final String token = tokenUtil.generateToken(userDetails, dev); + + return ResponseEntity.ok(new JwtAuthenticationResponse(token)); + } + + @RequestMapping(value = "${jwt.route.authentication.refresh}", method = RequestMethod.GET) + public ResponseEntity refreshAndGetAuthenticationToken(HttpServletRequest req){ + String token = req.getHeader(tokenHeader); + String username = tokenUtil.getUsernameFromToken(token); + JwtUser user = (JwtUser) userDetServ.loadUserByUsername(username); + + if(tokenUtil.canTokenBeRefreshed(token, user.getLastPasswordResetDate())){ + String refreshedToken = tokenUtil.refreshToken(token); + return ResponseEntity.ok(new JwtAuthenticationResponse(refreshedToken)); + } else { + return ResponseEntity.badRequest().body(null); + } + } +} diff --git a/src/main/java/com/revature/security/controllers/UserRestController.java b/src/main/java/com/revature/security/controllers/UserRestController.java new file mode 100644 index 0000000..ebcb8b9 --- /dev/null +++ b/src/main/java/com/revature/security/controllers/UserRestController.java @@ -0,0 +1,46 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security.controllers; + +import com.revature.security.JwtTokenUtil; +import com.revature.security.JwtUser; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +/** + * + * @author FayeRedd + */ + +@RestController +public class UserRestController { + + @Value("${jwt.header}") + private String tokenHeader; + + @Autowired + private JwtTokenUtil jwtTokenUtil; + + @Autowired + private UserDetailsService userDetailsService; + + @RequestMapping(value="user", method = RequestMethod.GET) + public JwtUser getAuthenticatedUser(HttpServletRequest req){ + + String token = req.getHeader(tokenHeader); + String username = jwtTokenUtil.getUsernameFromToken(token); + JwtUser user = (JwtUser) userDetailsService.loadUserByUsername(username); + + return user; + } +} \ No newline at end of file diff --git a/src/main/java/com/revature/security/exceptions/JwtTokenMissingException.java b/src/main/java/com/revature/security/exceptions/JwtTokenMissingException.java new file mode 100644 index 0000000..6c2a485 --- /dev/null +++ b/src/main/java/com/revature/security/exceptions/JwtTokenMissingException.java @@ -0,0 +1,19 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security.exceptions; + +/** + * + * @author FayeRedd + */ +public class JwtTokenMissingException extends RuntimeException{ + + public JwtTokenMissingException(){} + + public JwtTokenMissingException(String message){ + super(message); + } +} diff --git a/src/main/java/com/revature/security/repository/UserRepository.java b/src/main/java/com/revature/security/repository/UserRepository.java new file mode 100644 index 0000000..2fe4d2d --- /dev/null +++ b/src/main/java/com/revature/security/repository/UserRepository.java @@ -0,0 +1,17 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security.repository; + +import com.revature.model.security.User; +import org.springframework.data.jpa.repository.JpaRepository; + +/** + * + * @author FayeRedd + */ +public interface UserRepository extends JpaRepository { + User findByUsername(String username); +} diff --git a/src/main/java/com/revature/security/service/JwtAuthenticationResponse.java b/src/main/java/com/revature/security/service/JwtAuthenticationResponse.java new file mode 100644 index 0000000..784f40c --- /dev/null +++ b/src/main/java/com/revature/security/service/JwtAuthenticationResponse.java @@ -0,0 +1,27 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security.service; + +import java.io.Serializable; + +/** + * + * @author FayeRedd + */ +public class JwtAuthenticationResponse implements Serializable { + + private static final long serialVersionUID = 1250166508152483573L; + + private final String token; + + public JwtAuthenticationResponse(String token) { + this.token = token; + } + + public String getToken() { + return this.token; + } +} diff --git a/src/main/java/com/revature/security/service/JwtUserDetailsServiceImpl.java b/src/main/java/com/revature/security/service/JwtUserDetailsServiceImpl.java new file mode 100644 index 0000000..7f4128c --- /dev/null +++ b/src/main/java/com/revature/security/service/JwtUserDetailsServiceImpl.java @@ -0,0 +1,37 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security.service; + +import com.revature.model.security.User; +import com.revature.security.JwtUserFactory; +import com.revature.security.repository.UserRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +/** + * + * @author FayeRedd + */ +@Service +public class JwtUserDetailsServiceImpl implements UserDetailsService { + + @Autowired + private UserRepository userRepository; + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + User user = userRepository.findByUsername(username); + + if (user == null) { + throw new UsernameNotFoundException(String.format("No user found with username '%s'.", username)); + } else { + return JwtUserFactory.create(user); + } + } +} \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..b7c36fe --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,21 @@ +## YAML Template. +--- +server: + contextPath: + + +# JACKSON + +spring: + jackson: + serialization: + INDENT_OUTPUT: true + +jwt: + header: Authorization + secret: mySecret + expiration: 604800 + route: + authentication: + path: auth + refresh: refresh \ No newline at end of file From 10595c1beb3688fcd73bf75f9df8a4554ec337f9 Mon Sep 17 00:00:00 2001 From: Madison Date: Wed, 29 Mar 2017 09:33:35 -0700 Subject: [PATCH 02/19] update for readability and demo token generator --- .../java/com/revature/{ => config}/DataSourceConfig.java | 2 +- src/main/java/com/revature/{ => config}/WebConfig.java | 2 +- .../com/revature/security/JwtAuthenticationFilter.java | 1 + src/main/java/com/revature/security/JwtTokenUtil.java | 8 ++++++++ .../controllers/AuthenticationRestController.java | 4 ++++ .../revature/security/controllers/UserRestController.java | 2 ++ 6 files changed, 17 insertions(+), 2 deletions(-) rename src/main/java/com/revature/{ => config}/DataSourceConfig.java (96%) rename src/main/java/com/revature/{ => config}/WebConfig.java (97%) diff --git a/src/main/java/com/revature/DataSourceConfig.java b/src/main/java/com/revature/config/DataSourceConfig.java similarity index 96% rename from src/main/java/com/revature/DataSourceConfig.java rename to src/main/java/com/revature/config/DataSourceConfig.java index 79bfa5a..dd5925c 100644 --- a/src/main/java/com/revature/DataSourceConfig.java +++ b/src/main/java/com/revature/config/DataSourceConfig.java @@ -1,4 +1,4 @@ -package com.revature; +package com.revature.config; import javax.activation.DataSource; diff --git a/src/main/java/com/revature/WebConfig.java b/src/main/java/com/revature/config/WebConfig.java similarity index 97% rename from src/main/java/com/revature/WebConfig.java rename to src/main/java/com/revature/config/WebConfig.java index 4ecc141..4f1a47b 100644 --- a/src/main/java/com/revature/WebConfig.java +++ b/src/main/java/com/revature/config/WebConfig.java @@ -1,4 +1,4 @@ -package com.revature; +package com.revature.config; import java.time.LocalDate; import org.springframework.context.annotation.Configuration; diff --git a/src/main/java/com/revature/security/JwtAuthenticationFilter.java b/src/main/java/com/revature/security/JwtAuthenticationFilter.java index 5c66344..8298cb7 100644 --- a/src/main/java/com/revature/security/JwtAuthenticationFilter.java +++ b/src/main/java/com/revature/security/JwtAuthenticationFilter.java @@ -32,6 +32,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { @Autowired private UserDetailsService userDetailsService; + //This is the token generator. Can be replaced with future microservice providing/varifying tokens @Autowired private JwtTokenUtil jwtTokenUtil; diff --git a/src/main/java/com/revature/security/JwtTokenUtil.java b/src/main/java/com/revature/security/JwtTokenUtil.java index 64783a3..221960f 100644 --- a/src/main/java/com/revature/security/JwtTokenUtil.java +++ b/src/main/java/com/revature/security/JwtTokenUtil.java @@ -9,6 +9,7 @@ * * @author FayeRedd */ +import com.revature.security.JwtUser; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; @@ -22,6 +23,11 @@ import java.util.HashMap; import java.util.Map; +/* +* This class is the demo token generator/validator. It can be replaced in the future with +* a microservice providing these same features +*/ + @Component public class JwtTokenUtil implements Serializable { @@ -36,9 +42,11 @@ public class JwtTokenUtil implements Serializable { private static final String AUDIENCE_MOBILE = "mobile"; private static final String AUDIENCE_TABLET = "tablet"; + //This value is stored in the application.yml file @Value("${jwt.secret}") private String secret; + //This value is stored in the application.yml file @Value("${jwt.expiration}") private Long expiration; diff --git a/src/main/java/com/revature/security/controllers/AuthenticationRestController.java b/src/main/java/com/revature/security/controllers/AuthenticationRestController.java index ba28b27..4c2c468 100644 --- a/src/main/java/com/revature/security/controllers/AuthenticationRestController.java +++ b/src/main/java/com/revature/security/controllers/AuthenticationRestController.java @@ -34,18 +34,21 @@ @RestController public class AuthenticationRestController { + //This value can be found in the application.yml file @Value("${jwt.header}") private String tokenHeader; @Autowired private AuthenticationManager authMan; + //This is the token generator/validator. Can be replaced with future microservice providing/varifying tokens @Autowired private JwtTokenUtil tokenUtil; @Autowired private UserDetailsService userDetServ; + //This value can be found in the application.yml file @RequestMapping(value = "${jwt.route.authentication.path}", method = RequestMethod.POST) public ResponseEntity createAuthenticationToken(@RequestBody JwtAuthenticationRequest authReq, Device dev) throws AuthenticationException{ @@ -63,6 +66,7 @@ public ResponseEntity createAuthenticationToken(@RequestBody JwtAuthenticatio return ResponseEntity.ok(new JwtAuthenticationResponse(token)); } + //This value can be found in the application.yml file @RequestMapping(value = "${jwt.route.authentication.refresh}", method = RequestMethod.GET) public ResponseEntity refreshAndGetAuthenticationToken(HttpServletRequest req){ String token = req.getHeader(tokenHeader); diff --git a/src/main/java/com/revature/security/controllers/UserRestController.java b/src/main/java/com/revature/security/controllers/UserRestController.java index ebcb8b9..d484f86 100644 --- a/src/main/java/com/revature/security/controllers/UserRestController.java +++ b/src/main/java/com/revature/security/controllers/UserRestController.java @@ -25,9 +25,11 @@ @RestController public class UserRestController { + //This value is found in the application.yml file @Value("${jwt.header}") private String tokenHeader; + //This is the token generator/validator. Can be replaced with future microservice providing/varifying tokens @Autowired private JwtTokenUtil jwtTokenUtil; From 2809d71a472d9dbf07a2556f8726cd6b5933395f Mon Sep 17 00:00:00 2001 From: Madison Date: Wed, 29 Mar 2017 11:53:00 -0700 Subject: [PATCH 03/19] debugging --- pom.xml | 8 +++--- .../InterviewEvaluationsApplication.java | 1 + .../revature/model/security/Authority.java | 6 ++--- .../com/revature/model/security/User.java | 26 +++++++++---------- .../security/JwtAuthenticationEntryPoint.java | 7 ++++- .../security/JwtAuthenticationFilter.java | 2 +- .../com/revature/security/JwtTokenUtil.java | 2 +- .../security/repository/UserRepository.java | 5 ++++ .../service/JwtUserDetailsServiceImpl.java | 5 ++++ 9 files changed, 39 insertions(+), 23 deletions(-) diff --git a/pom.xml b/pom.xml index 2b2e740..ad40f09 100644 --- a/pom.xml +++ b/pom.xml @@ -75,10 +75,6 @@ - - org.springframework.boot - spring-boot-starter-web - org.springframework.boot spring-boot-starter-test @@ -167,6 +163,10 @@ JBoss Maven Release Repository https://repository.jboss.org/nexus/content/repositories/releases + + + + diff --git a/src/main/java/com/revature/InterviewEvaluationsApplication.java b/src/main/java/com/revature/InterviewEvaluationsApplication.java index 406a464..cc871b0 100644 --- a/src/main/java/com/revature/InterviewEvaluationsApplication.java +++ b/src/main/java/com/revature/InterviewEvaluationsApplication.java @@ -11,6 +11,7 @@ public class InterviewEvaluationsApplication { public static void main(String[] args) { + SpringApplication.run(InterviewEvaluationsApplication.class, args); } diff --git a/src/main/java/com/revature/model/security/Authority.java b/src/main/java/com/revature/model/security/Authority.java index 0a8f825..2242867 100644 --- a/src/main/java/com/revature/model/security/Authority.java +++ b/src/main/java/com/revature/model/security/Authority.java @@ -19,16 +19,16 @@ */ @Entity -@Table(name = "AUTHORITY") +@Table(name = "ie_AUTHORITY") public class Authority { @Id - @Column(name = "ID") + @Column(name = "a_authID") @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "authority_seq") @SequenceGenerator(name = "authority_seq", sequenceName = "authority_seq", allocationSize = 1) private Long id; - @Column(name = "NAME", length = 50) + @Column(name = "a_authorityName", length = 50) @NotNull @Enumerated(EnumType.STRING) private AuthorityName name; diff --git a/src/main/java/com/revature/model/security/User.java b/src/main/java/com/revature/model/security/User.java index d1dc7f1..26617f6 100644 --- a/src/main/java/com/revature/model/security/User.java +++ b/src/main/java/com/revature/model/security/User.java @@ -34,54 +34,54 @@ */ @Entity -@Table(name = "USER") +@Table(name = "ie_user") public class User { @Id - @Column(name = "ID") + @Column(name = "u_userID") @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_seq") @SequenceGenerator(name = "user_seq", sequenceName = "user_seq", allocationSize = 1) private Long id; - @Column(name = "USERNAME", length = 50, unique = true) + @Column(name = "u_username", length = 50, unique = true) @NotNull @Size(min = 4, max = 50) private String username; - @Column(name = "PASSWORD", length = 100) + @Column(name = "u_password", length = 100) @NotNull @Size(min = 4, max = 100) private String password; - @Column(name = "FIRSTNAME", length = 50) + @Column(name = "u_firstName", length = 50) @NotNull @Size(min = 4, max = 50) private String firstname; - @Column(name = "LASTNAME", length = 50) + @Column(name = "u_lastName", length = 50) @NotNull @Size(min = 4, max = 50) private String lastname; - @Column(name = "EMAIL", length = 50) + @Column(name = "u_email", length = 50) @NotNull @Size(min = 4, max = 50) private String email; - @Column(name = "ENABLED") + @Column(name = "u_enabled") @NotNull private Boolean enabled; - @Column(name = "LASTPASSWORDRESETDATE") + @Column(name = "u_lastpasswordresetdate") @Temporal(TemporalType.TIMESTAMP) @NotNull private Date lastPasswordResetDate; @ManyToMany(fetch = FetchType.EAGER) @JoinTable( - name = "USER_AUTHORITY", - joinColumns = {@JoinColumn(name = "USER_ID", referencedColumnName = "ID")}, - inverseJoinColumns = {@JoinColumn(name = "AUTHORITY_ID", referencedColumnName = "ID")}) + name = "ua_user_authority", + joinColumns = {@JoinColumn(name = "u_user_id", referencedColumnName = "u_userID")}, + inverseJoinColumns = {@JoinColumn(name = "a_authority_id", referencedColumnName = "a_authID")}) private List authorities; public Long getId() { @@ -154,5 +154,5 @@ public Date getLastPasswordResetDate() { public void setLastPasswordResetDate(Date lastPasswordResetDate) { this.lastPasswordResetDate = lastPasswordResetDate; - } + } } diff --git a/src/main/java/com/revature/security/JwtAuthenticationEntryPoint.java b/src/main/java/com/revature/security/JwtAuthenticationEntryPoint.java index bd1f293..6a73638 100644 --- a/src/main/java/com/revature/security/JwtAuthenticationEntryPoint.java +++ b/src/main/java/com/revature/security/JwtAuthenticationEntryPoint.java @@ -6,17 +6,22 @@ package com.revature.security; import java.io.IOException; +import java.io.Serializable; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; /** * * @author FayeRedd */ -public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint{ +@Component +public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable{ + private static final long serialVersionUID = -8970718410437077606L; + @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException { response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); diff --git a/src/main/java/com/revature/security/JwtAuthenticationFilter.java b/src/main/java/com/revature/security/JwtAuthenticationFilter.java index 8298cb7..2e20554 100644 --- a/src/main/java/com/revature/security/JwtAuthenticationFilter.java +++ b/src/main/java/com/revature/security/JwtAuthenticationFilter.java @@ -32,7 +32,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { @Autowired private UserDetailsService userDetailsService; - //This is the token generator. Can be replaced with future microservice providing/varifying tokens + //This is the token generator/validator. Can be replaced with future microservice providing/varifying tokens @Autowired private JwtTokenUtil jwtTokenUtil; diff --git a/src/main/java/com/revature/security/JwtTokenUtil.java b/src/main/java/com/revature/security/JwtTokenUtil.java index 221960f..e7522fd 100644 --- a/src/main/java/com/revature/security/JwtTokenUtil.java +++ b/src/main/java/com/revature/security/JwtTokenUtil.java @@ -9,7 +9,7 @@ * * @author FayeRedd */ -import com.revature.security.JwtUser; + import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; diff --git a/src/main/java/com/revature/security/repository/UserRepository.java b/src/main/java/com/revature/security/repository/UserRepository.java index 2fe4d2d..cb3b0e1 100644 --- a/src/main/java/com/revature/security/repository/UserRepository.java +++ b/src/main/java/com/revature/security/repository/UserRepository.java @@ -7,11 +7,16 @@ import com.revature.model.security.User; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; /** * * @author FayeRedd */ + +@Repository public interface UserRepository extends JpaRepository { + User findByUsername(String username); + } diff --git a/src/main/java/com/revature/security/service/JwtUserDetailsServiceImpl.java b/src/main/java/com/revature/security/service/JwtUserDetailsServiceImpl.java index 7f4128c..928d755 100644 --- a/src/main/java/com/revature/security/service/JwtUserDetailsServiceImpl.java +++ b/src/main/java/com/revature/security/service/JwtUserDetailsServiceImpl.java @@ -34,4 +34,9 @@ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundEx return JwtUserFactory.create(user); } } + +// @Override +// public UserDetails loadUserByUsername(String string) throws UsernameNotFoundException { +// throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. +// } } \ No newline at end of file From ff159cb190aa166936ac52161badd368836d4ea5 Mon Sep 17 00:00:00 2001 From: Madison Date: Wed, 29 Mar 2017 12:21:49 -0700 Subject: [PATCH 04/19] bugfix --- .../java/com/revature/InterviewEvaluationsApplication.java | 2 +- .../{security/repository => repositories}/UserRepository.java | 3 ++- .../revature/security/service/JwtUserDetailsServiceImpl.java | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) rename src/main/java/com/revature/{security/repository => repositories}/UserRepository.java (92%) diff --git a/src/main/java/com/revature/InterviewEvaluationsApplication.java b/src/main/java/com/revature/InterviewEvaluationsApplication.java index cc871b0..5b74add 100644 --- a/src/main/java/com/revature/InterviewEvaluationsApplication.java +++ b/src/main/java/com/revature/InterviewEvaluationsApplication.java @@ -11,7 +11,7 @@ public class InterviewEvaluationsApplication { public static void main(String[] args) { - + SpringApplication.run(InterviewEvaluationsApplication.class, args); } diff --git a/src/main/java/com/revature/security/repository/UserRepository.java b/src/main/java/com/revature/repositories/UserRepository.java similarity index 92% rename from src/main/java/com/revature/security/repository/UserRepository.java rename to src/main/java/com/revature/repositories/UserRepository.java index cb3b0e1..26dd61f 100644 --- a/src/main/java/com/revature/security/repository/UserRepository.java +++ b/src/main/java/com/revature/repositories/UserRepository.java @@ -3,7 +3,7 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package com.revature.security.repository; +package com.revature.repositories; import com.revature.model.security.User; import org.springframework.data.jpa.repository.JpaRepository; @@ -14,6 +14,7 @@ * @author FayeRedd */ + @Repository public interface UserRepository extends JpaRepository { diff --git a/src/main/java/com/revature/security/service/JwtUserDetailsServiceImpl.java b/src/main/java/com/revature/security/service/JwtUserDetailsServiceImpl.java index 928d755..7a4ae59 100644 --- a/src/main/java/com/revature/security/service/JwtUserDetailsServiceImpl.java +++ b/src/main/java/com/revature/security/service/JwtUserDetailsServiceImpl.java @@ -7,7 +7,7 @@ import com.revature.model.security.User; import com.revature.security.JwtUserFactory; -import com.revature.security.repository.UserRepository; +import com.revature.repositories.UserRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; From 7df2a9db3b0c418028641981bdd2e1347344c98c Mon Sep 17 00:00:00 2001 From: Madison Date: Wed, 29 Mar 2017 16:42:54 -0700 Subject: [PATCH 05/19] security tested, operational --- .../security/JwtAuthenticationFilter.java | 10 ++-- .../com/revature/security/JwtTokenTest.java | 48 +++++++++++++++++++ 2 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 src/test/java/com/revature/security/JwtTokenTest.java diff --git a/src/main/java/com/revature/security/JwtAuthenticationFilter.java b/src/main/java/com/revature/security/JwtAuthenticationFilter.java index 2e20554..b7f0917 100644 --- a/src/main/java/com/revature/security/JwtAuthenticationFilter.java +++ b/src/main/java/com/revature/security/JwtAuthenticationFilter.java @@ -10,8 +10,8 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +//import org.apache.commons.logging.Log; +//import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; @@ -27,7 +27,7 @@ */ public class JwtAuthenticationFilter extends OncePerRequestFilter { - private final Log logger = LogFactory.getLog(this.getClass()); + // private final Log myLogger = LogFactory.getLog(this.getClass()); @Autowired private UserDetailsService userDetailsService; @@ -45,7 +45,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse String username = jwtTokenUtil.getUsernameFromToken(authToken); - logger.info("checking authentication for das user " + username); + // myLogger.info("checking authentication for das user " + username); if(username != null && SecurityContextHolder.getContext().getAuthentication() == null){ UserDetails userDetails = this.userDetailsService.loadUserByUsername(username); @@ -55,7 +55,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); - logger.info("authenticated user " + username + ", setting security context"); + // myLogger.info("authenticated user " + username + ", setting security context"); SecurityContextHolder.getContext().setAuthentication(authentication); } diff --git a/src/test/java/com/revature/security/JwtTokenTest.java b/src/test/java/com/revature/security/JwtTokenTest.java new file mode 100644 index 0000000..5aaf2ef --- /dev/null +++ b/src/test/java/com/revature/security/JwtTokenTest.java @@ -0,0 +1,48 @@ +/* + * The MIT License + * + */ +package com.revature.security; + +import java.util.HashMap; +import java.util.Map; +import org.assertj.core.util.DateUtil; +import static org.assertj.core.api.Assertions.assertThat; +import org.junit.Before; +import org.junit.Test; +import org.springframework.test.util.ReflectionTestUtils; + +/** + * + * @author FayeRedd + */ +public class JwtTokenTest { + private JwtTokenUtil jwtTokenUtil; + + @Before + public void init() { + jwtTokenUtil = new JwtTokenUtil(); + ReflectionTestUtils.setField(jwtTokenUtil, "expiration", 3600000L); + ReflectionTestUtils.setField(jwtTokenUtil, "secret", "mySecret"); + } + + @Test + public void testGenerateTokenGeneratesDifferentTokensForDifferentCreationDates() throws Exception { + final Map claims = createClaims("2016-09-08T03:00:00"); + final String token = jwtTokenUtil.generateToken(claims); + + final Map claimsForLaterToken = createClaims("2016-09-08T08:00:00"); + final String laterToken = jwtTokenUtil.generateToken(claimsForLaterToken); + + assertThat(token).isNotEqualTo(laterToken); + } + + private Map createClaims(String creationDate) { + Map claims = new HashMap(); + claims.put(JwtTokenUtil.CLAIM_KEY_USERNAME, "testUser"); + claims.put(JwtTokenUtil.CLAIM_KEY_AUDIENCE, "testAudience"); + claims.put(JwtTokenUtil.CLAIM_KEY_CREATED, DateUtil.parseDatetime(creationDate)); + return claims; + } + +} From 70d54ade77d1d734abf7dae6aa8dab8483a665bd Mon Sep 17 00:00:00 2001 From: Madison Date: Tue, 28 Mar 2017 15:22:10 -0700 Subject: [PATCH 06/19] Add security compatibility, temporary token generator; testing needed. --- pom.xml | 31 ++- .../revature/config/WebSecurityConfig.java | 92 +++++++++ .../revature/model/security/Authority.java | 62 ++++++ .../model/security/AuthorityName.java | 14 ++ .../com/revature/model/security/User.java | 158 ++++++++++++++++ .../security/JwtAuthenticationEntryPoint.java | 25 +++ .../security/JwtAuthenticationFilter.java | 64 +++++++ .../security/JwtAuthenticationRequest.java | 45 +++++ .../JwtAuthenticationSuccessHandler.java | 24 +++ .../com/revature/security/JwtTokenUtil.java | 176 ++++++++++++++++++ .../java/com/revature/security/JwtUser.java | 113 +++++++++++ .../com/revature/security/JwtUserFactory.java | 45 +++++ .../AuthenticationRestController.java | 79 ++++++++ .../controllers/UserRestController.java | 46 +++++ .../exceptions/JwtTokenMissingException.java | 19 ++ .../security/repository/UserRepository.java | 17 ++ .../service/JwtAuthenticationResponse.java | 27 +++ .../service/JwtUserDetailsServiceImpl.java | 37 ++++ src/main/resources/application.yml | 21 +++ 19 files changed, 1094 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/revature/config/WebSecurityConfig.java create mode 100644 src/main/java/com/revature/model/security/Authority.java create mode 100644 src/main/java/com/revature/model/security/AuthorityName.java create mode 100644 src/main/java/com/revature/model/security/User.java create mode 100644 src/main/java/com/revature/security/JwtAuthenticationEntryPoint.java create mode 100644 src/main/java/com/revature/security/JwtAuthenticationFilter.java create mode 100644 src/main/java/com/revature/security/JwtAuthenticationRequest.java create mode 100644 src/main/java/com/revature/security/JwtAuthenticationSuccessHandler.java create mode 100644 src/main/java/com/revature/security/JwtTokenUtil.java create mode 100644 src/main/java/com/revature/security/JwtUser.java create mode 100644 src/main/java/com/revature/security/JwtUserFactory.java create mode 100644 src/main/java/com/revature/security/controllers/AuthenticationRestController.java create mode 100644 src/main/java/com/revature/security/controllers/UserRestController.java create mode 100644 src/main/java/com/revature/security/exceptions/JwtTokenMissingException.java create mode 100644 src/main/java/com/revature/security/repository/UserRepository.java create mode 100644 src/main/java/com/revature/security/service/JwtAuthenticationResponse.java create mode 100644 src/main/java/com/revature/security/service/JwtUserDetailsServiceImpl.java create mode 100644 src/main/resources/application.yml diff --git a/pom.xml b/pom.xml index 2978103..2b2e740 100644 --- a/pom.xml +++ b/pom.xml @@ -113,7 +113,36 @@ spring-boot-devtools true - + + org.springframework.mobile + spring-mobile-device + 1.1.5.RELEASE + jar + + + org.springframework.security + spring-security-core + 4.2.1.RELEASE + jar + + + org.springframework.security + spring-security-web + 4.2.1.RELEASE + jar + + + io.jsonwebtoken + jjwt + 0.7.0 + jar + + + org.springframework.security + spring-security-config + 4.2.1.RELEASE + jar + diff --git a/src/main/java/com/revature/config/WebSecurityConfig.java b/src/main/java/com/revature/config/WebSecurityConfig.java new file mode 100644 index 0000000..b970f06 --- /dev/null +++ b/src/main/java/com/revature/config/WebSecurityConfig.java @@ -0,0 +1,92 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.config; + +import com.revature.security.JwtAuthenticationEntryPoint; +import com.revature.security.JwtAuthenticationFilter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +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.config.http.SessionCreationPolicy; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +/** + * + * @author FayeRedd + */ + +@SuppressWarnings("SpringJavaAutowiringInspection") +@Configuration +@EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true) +public class WebSecurityConfig extends WebSecurityConfigurerAdapter{ + + @Autowired + private JwtAuthenticationEntryPoint unauthorizedHandler; + + @Autowired + private UserDetailsService userDetailsService; + + @Autowired + public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception{ + authenticationManagerBuilder + .userDetailsService(this.userDetailsService) + .passwordEncoder(passwordEncoder()); + } + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Bean + public JwtAuthenticationFilter authenticationFilterBean() throws Exception { + return new JwtAuthenticationFilter(); + } + + @Override + protected void configure(HttpSecurity httpSecurity) throws Exception{ + httpSecurity + .csrf().disable() + + .exceptionHandling().authenticationEntryPoint(unauthorizedHandler) + + .and() + + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) + + .and() + + .authorizeRequests() + + .antMatchers( + HttpMethod.GET, + "/", + "/*.html", + "/favicon.ico", + "/**/*.html", + "/**/*.css", + "/**/*.js" + ).permitAll() + .antMatchers("/auth/**").permitAll() + .anyRequest().authenticated(); + + httpSecurity + .addFilterBefore(authenticationFilterBean(), UsernamePasswordAuthenticationFilter.class); + + httpSecurity.headers().cacheControl(); + + } +} diff --git a/src/main/java/com/revature/model/security/Authority.java b/src/main/java/com/revature/model/security/Authority.java new file mode 100644 index 0000000..0a8f825 --- /dev/null +++ b/src/main/java/com/revature/model/security/Authority.java @@ -0,0 +1,62 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.model.security; + +/** + * + * @author FayeRedd + */ +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import java.util.List; + +/* +This is a placeholder Entity for an "Authority" POJO. Feel free to modify/edit as needed +for compatibility with actual database Table +*/ + +@Entity +@Table(name = "AUTHORITY") +public class Authority { + + @Id + @Column(name = "ID") + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "authority_seq") + @SequenceGenerator(name = "authority_seq", sequenceName = "authority_seq", allocationSize = 1) + private Long id; + + @Column(name = "NAME", length = 50) + @NotNull + @Enumerated(EnumType.STRING) + private AuthorityName name; + + @ManyToMany(mappedBy = "authorities", fetch = FetchType.LAZY) + private List users; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public AuthorityName getName() { + return name; + } + + public void setName(AuthorityName name) { + this.name = name; + } + + public List getUsers() { + return users; + } + + public void setUsers(List users) { + this.users = users; + } +} \ No newline at end of file diff --git a/src/main/java/com/revature/model/security/AuthorityName.java b/src/main/java/com/revature/model/security/AuthorityName.java new file mode 100644 index 0000000..95d8929 --- /dev/null +++ b/src/main/java/com/revature/model/security/AuthorityName.java @@ -0,0 +1,14 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.model.security; + +/** + * + * @author FayeRedd + */ +public enum AuthorityName { + ROLE_USER, ROLE_ADMIN +} diff --git a/src/main/java/com/revature/model/security/User.java b/src/main/java/com/revature/model/security/User.java new file mode 100644 index 0000000..d1dc7f1 --- /dev/null +++ b/src/main/java/com/revature/model/security/User.java @@ -0,0 +1,158 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.model.security; + +/** + * + * @author FayeRedd + */ +import java.util.Date; +import java.util.List; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToMany; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +/* +This is a placeholder Entity for the User POJO. Feel free to modify/edit as needed +for compatibility with actual database Table +*/ + +@Entity +@Table(name = "USER") +public class User { + + @Id + @Column(name = "ID") + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_seq") + @SequenceGenerator(name = "user_seq", sequenceName = "user_seq", allocationSize = 1) + private Long id; + + @Column(name = "USERNAME", length = 50, unique = true) + @NotNull + @Size(min = 4, max = 50) + private String username; + + @Column(name = "PASSWORD", length = 100) + @NotNull + @Size(min = 4, max = 100) + private String password; + + @Column(name = "FIRSTNAME", length = 50) + @NotNull + @Size(min = 4, max = 50) + private String firstname; + + @Column(name = "LASTNAME", length = 50) + @NotNull + @Size(min = 4, max = 50) + private String lastname; + + @Column(name = "EMAIL", length = 50) + @NotNull + @Size(min = 4, max = 50) + private String email; + + @Column(name = "ENABLED") + @NotNull + private Boolean enabled; + + @Column(name = "LASTPASSWORDRESETDATE") + @Temporal(TemporalType.TIMESTAMP) + @NotNull + private Date lastPasswordResetDate; + + @ManyToMany(fetch = FetchType.EAGER) + @JoinTable( + name = "USER_AUTHORITY", + joinColumns = {@JoinColumn(name = "USER_ID", referencedColumnName = "ID")}, + inverseJoinColumns = {@JoinColumn(name = "AUTHORITY_ID", referencedColumnName = "ID")}) + private List authorities; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + 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 getFirstname() { + return firstname; + } + + public void setFirstname(String firstname) { + this.firstname = firstname; + } + + public String getLastname() { + return lastname; + } + + public void setLastname(String lastname) { + this.lastname = lastname; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public Boolean getEnabled() { + return enabled; + } + + public void setEnabled(Boolean enabled) { + this.enabled = enabled; + } + + public List getAuthorities() { + return authorities; + } + + public void setAuthorities(List authorities) { + this.authorities = authorities; + } + + public Date getLastPasswordResetDate() { + return lastPasswordResetDate; + } + + public void setLastPasswordResetDate(Date lastPasswordResetDate) { + this.lastPasswordResetDate = lastPasswordResetDate; + } +} diff --git a/src/main/java/com/revature/security/JwtAuthenticationEntryPoint.java b/src/main/java/com/revature/security/JwtAuthenticationEntryPoint.java new file mode 100644 index 0000000..bd1f293 --- /dev/null +++ b/src/main/java/com/revature/security/JwtAuthenticationEntryPoint.java @@ -0,0 +1,25 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security; + +import java.io.IOException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; + +/** + * + * @author FayeRedd + */ +public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint{ + + @Override + public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException { + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); + } + +} diff --git a/src/main/java/com/revature/security/JwtAuthenticationFilter.java b/src/main/java/com/revature/security/JwtAuthenticationFilter.java new file mode 100644 index 0000000..5c66344 --- /dev/null +++ b/src/main/java/com/revature/security/JwtAuthenticationFilter.java @@ -0,0 +1,64 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security; + +import java.io.IOException; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.web.filter.OncePerRequestFilter; + +/** + * + * @author FayeRedd + */ +public class JwtAuthenticationFilter extends OncePerRequestFilter { + + private final Log logger = LogFactory.getLog(this.getClass()); + + @Autowired + private UserDetailsService userDetailsService; + + @Autowired + private JwtTokenUtil jwtTokenUtil; + + @Value("Authorization") + private String tokenHeader; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { + String authToken = request.getHeader(this.tokenHeader); + + String username = jwtTokenUtil.getUsernameFromToken(authToken); + + logger.info("checking authentication for das user " + username); + + if(username != null && SecurityContextHolder.getContext().getAuthentication() == null){ + UserDetails userDetails = this.userDetailsService.loadUserByUsername(username); + + if(jwtTokenUtil.validateToken(authToken, userDetails)){ + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); + + authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + + logger.info("authenticated user " + username + ", setting security context"); + + SecurityContextHolder.getContext().setAuthentication(authentication); + } + } + chain.doFilter(request, response); + } +} diff --git a/src/main/java/com/revature/security/JwtAuthenticationRequest.java b/src/main/java/com/revature/security/JwtAuthenticationRequest.java new file mode 100644 index 0000000..c6555c9 --- /dev/null +++ b/src/main/java/com/revature/security/JwtAuthenticationRequest.java @@ -0,0 +1,45 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security; + +import java.io.Serializable; + +/** + * + * @author FayeRedd + */ +public class JwtAuthenticationRequest implements Serializable { + + private static final long serialVersionUID = -8445943548965154778L; + + private String username; + private String password; + + public JwtAuthenticationRequest() { + super(); + } + + public JwtAuthenticationRequest(String username, String password) { + this.setUsername(username); + this.setPassword(password); + } + + public String getUsername() { + return this.username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return this.password; + } + + public void setPassword(String password) { + this.password = password; + } +} diff --git a/src/main/java/com/revature/security/JwtAuthenticationSuccessHandler.java b/src/main/java/com/revature/security/JwtAuthenticationSuccessHandler.java new file mode 100644 index 0000000..a7ee1e2 --- /dev/null +++ b/src/main/java/com/revature/security/JwtAuthenticationSuccessHandler.java @@ -0,0 +1,24 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security; + +import java.io.IOException; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.springframework.security.core.Authentication; +import org.springframework.security.web.authentication.AuthenticationSuccessHandler; + +/** + * + * @author FayeRedd + */ +public class JwtAuthenticationSuccessHandler implements AuthenticationSuccessHandler{ + + @Override + public void onAuthenticationSuccess(HttpServletRequest hsr, HttpServletResponse hsr1, Authentication a) throws IOException, ServletException {} + +} diff --git a/src/main/java/com/revature/security/JwtTokenUtil.java b/src/main/java/com/revature/security/JwtTokenUtil.java new file mode 100644 index 0000000..64783a3 --- /dev/null +++ b/src/main/java/com/revature/security/JwtTokenUtil.java @@ -0,0 +1,176 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security; + +/** + * + * @author FayeRedd + */ +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.mobile.device.Device; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Component; + +import java.io.Serializable; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +@Component +public class JwtTokenUtil implements Serializable { + + private static final long serialVersionUID = -3301605591108950415L; + + static final String CLAIM_KEY_USERNAME = "sub"; + static final String CLAIM_KEY_AUDIENCE = "audience"; + static final String CLAIM_KEY_CREATED = "created"; + + private static final String AUDIENCE_UNKNOWN = "unknown"; + private static final String AUDIENCE_WEB = "web"; + private static final String AUDIENCE_MOBILE = "mobile"; + private static final String AUDIENCE_TABLET = "tablet"; + + @Value("${jwt.secret}") + private String secret; + + @Value("${jwt.expiration}") + private Long expiration; + + public String getUsernameFromToken(String token) { + String username; + try { + final Claims claims = getClaimsFromToken(token); + username = claims.getSubject(); + } catch (Exception e) { + username = null; + } + return username; + } + + public Date getCreatedDateFromToken(String token) { + Date created; + try { + final Claims claims = getClaimsFromToken(token); + created = new Date((Long) claims.get(CLAIM_KEY_CREATED)); + } catch (Exception e) { + created = null; + } + return created; + } + + public Date getExpirationDateFromToken(String token) { + Date expires; + try { + final Claims claims = getClaimsFromToken(token); + expires = claims.getExpiration(); + } catch (Exception e) { + expires = null; + } + return expires; + } + + public String getAudienceFromToken(String token) { + String audience; + try { + final Claims claims = getClaimsFromToken(token); + audience = (String) claims.get(CLAIM_KEY_AUDIENCE); + } catch (Exception e) { + audience = null; + } + return audience; + } + + private Claims getClaimsFromToken(String token) { + Claims claims; + try { + claims = Jwts.parser() + .setSigningKey(secret) + .parseClaimsJws(token) + .getBody(); + } catch (Exception e) { + claims = null; + } + return claims; + } + + private Date generateExpirationDate() { + return new Date(System.currentTimeMillis() + expiration * 1000); + } + + private Boolean isTokenExpired(String token) { + final Date expires = getExpirationDateFromToken(token); + return expires.before(new Date()); + } + + private Boolean isCreatedBeforeLastPasswordReset(Date created, Date lastPasswordReset) { + return (lastPasswordReset != null && created.before(lastPasswordReset)); + } + + private String generateAudience(Device device) { + String audience = AUDIENCE_UNKNOWN; + if (device.isNormal()) { + audience = AUDIENCE_WEB; + } else if (device.isTablet()) { + audience = AUDIENCE_TABLET; + } else if (device.isMobile()) { + audience = AUDIENCE_MOBILE; + } + return audience; + } + + private Boolean ignoreTokenExpiration(String token) { + String audience = getAudienceFromToken(token); + return (AUDIENCE_TABLET.equals(audience) || AUDIENCE_MOBILE.equals(audience)); + } + + public String generateToken(UserDetails userDetails, Device device) { + Map claims = new HashMap<>(); + claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername()); + claims.put(CLAIM_KEY_AUDIENCE, generateAudience(device)); + claims.put(CLAIM_KEY_CREATED, new Date()); + return generateToken(claims); + } + + String generateToken(Map claims) { + return Jwts.builder() + .setClaims(claims) + .setExpiration(generateExpirationDate()) + .signWith(SignatureAlgorithm.HS512, secret) + .compact(); + } + + public Boolean canTokenBeRefreshed(String token, Date lastPasswordReset) { + final Date created = getCreatedDateFromToken(token); + return !isCreatedBeforeLastPasswordReset(created, lastPasswordReset) + && (!isTokenExpired(token) || ignoreTokenExpiration(token)); + } + + public String refreshToken(String token) { + String refreshedToken; + try { + final Claims claims = getClaimsFromToken(token); + claims.put(CLAIM_KEY_CREATED, new Date()); + refreshedToken = generateToken(claims); + } catch (Exception e) { + refreshedToken = null; + } + return refreshedToken; + } + + public Boolean validateToken(String token, UserDetails userDetails) { + JwtUser user = (JwtUser) userDetails; + final String username = getUsernameFromToken(token); + final Date created = getCreatedDateFromToken(token); + //final Date expiration = getExpirationDateFromToken(token); + return ( + username.equals(user.getUsername()) + && !isTokenExpired(token) + && !isCreatedBeforeLastPasswordReset(created, user.getLastPasswordResetDate())); + } +} \ No newline at end of file diff --git a/src/main/java/com/revature/security/JwtUser.java b/src/main/java/com/revature/security/JwtUser.java new file mode 100644 index 0000000..6f15b77 --- /dev/null +++ b/src/main/java/com/revature/security/JwtUser.java @@ -0,0 +1,113 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security; + +/** + * + * @author FayeRedd + */ +import java.util.Collection; +import java.util.Date; + +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +public class JwtUser implements UserDetails { + + private final Long id; + private final String username; + private final String firstname; + private final String lastname; + private final String password; + private final String email; + private final Collection authorities; + private final boolean enabled; + private final Date lastPasswordResetDate; + + public JwtUser( + Long id, + String username, + String firstname, + String lastname, + String email, + String password, Collection authorities, + boolean enabled, + Date lastPasswordResetDate + ) { + this.id = id; + this.username = username; + this.firstname = firstname; + this.lastname = lastname; + this.email = email; + this.password = password; + this.authorities = authorities; + this.enabled = enabled; + this.lastPasswordResetDate = lastPasswordResetDate; + } + + @JsonIgnore + public Long getId() { + return id; + } + + @Override + public String getUsername() { + return username; + } + + @JsonIgnore + @Override + public boolean isAccountNonExpired() { + return true; + } + + @JsonIgnore + @Override + public boolean isAccountNonLocked() { + return true; + } + + @JsonIgnore + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + public String getFirstname() { + return firstname; + } + + public String getLastname() { + return lastname; + } + + public String getEmail() { + return email; + } + + @JsonIgnore + @Override + public String getPassword() { + return password; + } + + @Override + public Collection getAuthorities() { + return authorities; + } + + @Override + public boolean isEnabled() { + return enabled; + } + + @JsonIgnore + public Date getLastPasswordResetDate() { + return lastPasswordResetDate; + } +} diff --git a/src/main/java/com/revature/security/JwtUserFactory.java b/src/main/java/com/revature/security/JwtUserFactory.java new file mode 100644 index 0000000..4bdd5b4 --- /dev/null +++ b/src/main/java/com/revature/security/JwtUserFactory.java @@ -0,0 +1,45 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security; + +import com.revature.model.security.Authority; +import com.revature.model.security.User; +import java.util.List; +import java.util.stream.Collectors; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; + + + +/** + * + * @author FayeRedd + */ +public class JwtUserFactory { + + private JwtUserFactory(){} + + public static JwtUser create(User user){ + return new JwtUser( + user.getId(), + user.getUsername(), + user.getFirstname(), + user.getLastname(), + user.getEmail(), + user.getPassword(), + mapToGrantedAuthorities(user.getAuthorities()), + user.getEnabled(), + user.getLastPasswordResetDate() + ); + } + + private static List mapToGrantedAuthorities(List authorities) { + return authorities.stream() + .map(authority -> new SimpleGrantedAuthority(authority.getName().name())) + .collect(Collectors.toList()); + } + +} diff --git a/src/main/java/com/revature/security/controllers/AuthenticationRestController.java b/src/main/java/com/revature/security/controllers/AuthenticationRestController.java new file mode 100644 index 0000000..ba28b27 --- /dev/null +++ b/src/main/java/com/revature/security/controllers/AuthenticationRestController.java @@ -0,0 +1,79 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security.controllers; + +import com.revature.security.JwtAuthenticationRequest; +import com.revature.security.JwtTokenUtil; +import com.revature.security.JwtUser; +import com.revature.security.service.JwtAuthenticationResponse; +import javax.servlet.http.HttpServletRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.ResponseEntity; +import org.springframework.mobile.device.Device; +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.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.security.core.userdetails.UserDetails; + +/** + * + * @author FayeRedd + */ + +@RestController +public class AuthenticationRestController { + + @Value("${jwt.header}") + private String tokenHeader; + + @Autowired + private AuthenticationManager authMan; + + @Autowired + private JwtTokenUtil tokenUtil; + + @Autowired + private UserDetailsService userDetServ; + + @RequestMapping(value = "${jwt.route.authentication.path}", method = RequestMethod.POST) + public ResponseEntity createAuthenticationToken(@RequestBody JwtAuthenticationRequest authReq, Device dev) throws AuthenticationException{ + + final Authentication authentication = authMan.authenticate( + new UsernamePasswordAuthenticationToken( + authReq.getUsername(), + authReq.getPassword()) + ); + + SecurityContextHolder.getContext().setAuthentication(authentication); + + final UserDetails userDetails = userDetServ.loadUserByUsername(authReq.getUsername()); + final String token = tokenUtil.generateToken(userDetails, dev); + + return ResponseEntity.ok(new JwtAuthenticationResponse(token)); + } + + @RequestMapping(value = "${jwt.route.authentication.refresh}", method = RequestMethod.GET) + public ResponseEntity refreshAndGetAuthenticationToken(HttpServletRequest req){ + String token = req.getHeader(tokenHeader); + String username = tokenUtil.getUsernameFromToken(token); + JwtUser user = (JwtUser) userDetServ.loadUserByUsername(username); + + if(tokenUtil.canTokenBeRefreshed(token, user.getLastPasswordResetDate())){ + String refreshedToken = tokenUtil.refreshToken(token); + return ResponseEntity.ok(new JwtAuthenticationResponse(refreshedToken)); + } else { + return ResponseEntity.badRequest().body(null); + } + } +} diff --git a/src/main/java/com/revature/security/controllers/UserRestController.java b/src/main/java/com/revature/security/controllers/UserRestController.java new file mode 100644 index 0000000..ebcb8b9 --- /dev/null +++ b/src/main/java/com/revature/security/controllers/UserRestController.java @@ -0,0 +1,46 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security.controllers; + +import com.revature.security.JwtTokenUtil; +import com.revature.security.JwtUser; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +/** + * + * @author FayeRedd + */ + +@RestController +public class UserRestController { + + @Value("${jwt.header}") + private String tokenHeader; + + @Autowired + private JwtTokenUtil jwtTokenUtil; + + @Autowired + private UserDetailsService userDetailsService; + + @RequestMapping(value="user", method = RequestMethod.GET) + public JwtUser getAuthenticatedUser(HttpServletRequest req){ + + String token = req.getHeader(tokenHeader); + String username = jwtTokenUtil.getUsernameFromToken(token); + JwtUser user = (JwtUser) userDetailsService.loadUserByUsername(username); + + return user; + } +} \ No newline at end of file diff --git a/src/main/java/com/revature/security/exceptions/JwtTokenMissingException.java b/src/main/java/com/revature/security/exceptions/JwtTokenMissingException.java new file mode 100644 index 0000000..6c2a485 --- /dev/null +++ b/src/main/java/com/revature/security/exceptions/JwtTokenMissingException.java @@ -0,0 +1,19 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security.exceptions; + +/** + * + * @author FayeRedd + */ +public class JwtTokenMissingException extends RuntimeException{ + + public JwtTokenMissingException(){} + + public JwtTokenMissingException(String message){ + super(message); + } +} diff --git a/src/main/java/com/revature/security/repository/UserRepository.java b/src/main/java/com/revature/security/repository/UserRepository.java new file mode 100644 index 0000000..2fe4d2d --- /dev/null +++ b/src/main/java/com/revature/security/repository/UserRepository.java @@ -0,0 +1,17 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security.repository; + +import com.revature.model.security.User; +import org.springframework.data.jpa.repository.JpaRepository; + +/** + * + * @author FayeRedd + */ +public interface UserRepository extends JpaRepository { + User findByUsername(String username); +} diff --git a/src/main/java/com/revature/security/service/JwtAuthenticationResponse.java b/src/main/java/com/revature/security/service/JwtAuthenticationResponse.java new file mode 100644 index 0000000..784f40c --- /dev/null +++ b/src/main/java/com/revature/security/service/JwtAuthenticationResponse.java @@ -0,0 +1,27 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security.service; + +import java.io.Serializable; + +/** + * + * @author FayeRedd + */ +public class JwtAuthenticationResponse implements Serializable { + + private static final long serialVersionUID = 1250166508152483573L; + + private final String token; + + public JwtAuthenticationResponse(String token) { + this.token = token; + } + + public String getToken() { + return this.token; + } +} diff --git a/src/main/java/com/revature/security/service/JwtUserDetailsServiceImpl.java b/src/main/java/com/revature/security/service/JwtUserDetailsServiceImpl.java new file mode 100644 index 0000000..7f4128c --- /dev/null +++ b/src/main/java/com/revature/security/service/JwtUserDetailsServiceImpl.java @@ -0,0 +1,37 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security.service; + +import com.revature.model.security.User; +import com.revature.security.JwtUserFactory; +import com.revature.security.repository.UserRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +/** + * + * @author FayeRedd + */ +@Service +public class JwtUserDetailsServiceImpl implements UserDetailsService { + + @Autowired + private UserRepository userRepository; + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + User user = userRepository.findByUsername(username); + + if (user == null) { + throw new UsernameNotFoundException(String.format("No user found with username '%s'.", username)); + } else { + return JwtUserFactory.create(user); + } + } +} \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..b7c36fe --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,21 @@ +## YAML Template. +--- +server: + contextPath: + + +# JACKSON + +spring: + jackson: + serialization: + INDENT_OUTPUT: true + +jwt: + header: Authorization + secret: mySecret + expiration: 604800 + route: + authentication: + path: auth + refresh: refresh \ No newline at end of file From f5b81d027da82d11627054bb922ac539795103a7 Mon Sep 17 00:00:00 2001 From: Madison Date: Wed, 29 Mar 2017 09:33:35 -0700 Subject: [PATCH 07/19] update for readability and demo token generator --- .../java/com/revature/{ => config}/DataSourceConfig.java | 2 +- src/main/java/com/revature/{ => config}/WebConfig.java | 2 +- .../com/revature/security/JwtAuthenticationFilter.java | 1 + src/main/java/com/revature/security/JwtTokenUtil.java | 8 ++++++++ .../controllers/AuthenticationRestController.java | 4 ++++ .../revature/security/controllers/UserRestController.java | 2 ++ 6 files changed, 17 insertions(+), 2 deletions(-) rename src/main/java/com/revature/{ => config}/DataSourceConfig.java (96%) rename src/main/java/com/revature/{ => config}/WebConfig.java (97%) diff --git a/src/main/java/com/revature/DataSourceConfig.java b/src/main/java/com/revature/config/DataSourceConfig.java similarity index 96% rename from src/main/java/com/revature/DataSourceConfig.java rename to src/main/java/com/revature/config/DataSourceConfig.java index 79bfa5a..dd5925c 100644 --- a/src/main/java/com/revature/DataSourceConfig.java +++ b/src/main/java/com/revature/config/DataSourceConfig.java @@ -1,4 +1,4 @@ -package com.revature; +package com.revature.config; import javax.activation.DataSource; diff --git a/src/main/java/com/revature/WebConfig.java b/src/main/java/com/revature/config/WebConfig.java similarity index 97% rename from src/main/java/com/revature/WebConfig.java rename to src/main/java/com/revature/config/WebConfig.java index 4ecc141..4f1a47b 100644 --- a/src/main/java/com/revature/WebConfig.java +++ b/src/main/java/com/revature/config/WebConfig.java @@ -1,4 +1,4 @@ -package com.revature; +package com.revature.config; import java.time.LocalDate; import org.springframework.context.annotation.Configuration; diff --git a/src/main/java/com/revature/security/JwtAuthenticationFilter.java b/src/main/java/com/revature/security/JwtAuthenticationFilter.java index 5c66344..8298cb7 100644 --- a/src/main/java/com/revature/security/JwtAuthenticationFilter.java +++ b/src/main/java/com/revature/security/JwtAuthenticationFilter.java @@ -32,6 +32,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { @Autowired private UserDetailsService userDetailsService; + //This is the token generator. Can be replaced with future microservice providing/varifying tokens @Autowired private JwtTokenUtil jwtTokenUtil; diff --git a/src/main/java/com/revature/security/JwtTokenUtil.java b/src/main/java/com/revature/security/JwtTokenUtil.java index 64783a3..221960f 100644 --- a/src/main/java/com/revature/security/JwtTokenUtil.java +++ b/src/main/java/com/revature/security/JwtTokenUtil.java @@ -9,6 +9,7 @@ * * @author FayeRedd */ +import com.revature.security.JwtUser; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; @@ -22,6 +23,11 @@ import java.util.HashMap; import java.util.Map; +/* +* This class is the demo token generator/validator. It can be replaced in the future with +* a microservice providing these same features +*/ + @Component public class JwtTokenUtil implements Serializable { @@ -36,9 +42,11 @@ public class JwtTokenUtil implements Serializable { private static final String AUDIENCE_MOBILE = "mobile"; private static final String AUDIENCE_TABLET = "tablet"; + //This value is stored in the application.yml file @Value("${jwt.secret}") private String secret; + //This value is stored in the application.yml file @Value("${jwt.expiration}") private Long expiration; diff --git a/src/main/java/com/revature/security/controllers/AuthenticationRestController.java b/src/main/java/com/revature/security/controllers/AuthenticationRestController.java index ba28b27..4c2c468 100644 --- a/src/main/java/com/revature/security/controllers/AuthenticationRestController.java +++ b/src/main/java/com/revature/security/controllers/AuthenticationRestController.java @@ -34,18 +34,21 @@ @RestController public class AuthenticationRestController { + //This value can be found in the application.yml file @Value("${jwt.header}") private String tokenHeader; @Autowired private AuthenticationManager authMan; + //This is the token generator/validator. Can be replaced with future microservice providing/varifying tokens @Autowired private JwtTokenUtil tokenUtil; @Autowired private UserDetailsService userDetServ; + //This value can be found in the application.yml file @RequestMapping(value = "${jwt.route.authentication.path}", method = RequestMethod.POST) public ResponseEntity createAuthenticationToken(@RequestBody JwtAuthenticationRequest authReq, Device dev) throws AuthenticationException{ @@ -63,6 +66,7 @@ public ResponseEntity createAuthenticationToken(@RequestBody JwtAuthenticatio return ResponseEntity.ok(new JwtAuthenticationResponse(token)); } + //This value can be found in the application.yml file @RequestMapping(value = "${jwt.route.authentication.refresh}", method = RequestMethod.GET) public ResponseEntity refreshAndGetAuthenticationToken(HttpServletRequest req){ String token = req.getHeader(tokenHeader); diff --git a/src/main/java/com/revature/security/controllers/UserRestController.java b/src/main/java/com/revature/security/controllers/UserRestController.java index ebcb8b9..d484f86 100644 --- a/src/main/java/com/revature/security/controllers/UserRestController.java +++ b/src/main/java/com/revature/security/controllers/UserRestController.java @@ -25,9 +25,11 @@ @RestController public class UserRestController { + //This value is found in the application.yml file @Value("${jwt.header}") private String tokenHeader; + //This is the token generator/validator. Can be replaced with future microservice providing/varifying tokens @Autowired private JwtTokenUtil jwtTokenUtil; From d6c09b9d9ff7a0dec08ae2575db8e427c1e0933f Mon Sep 17 00:00:00 2001 From: Madison Date: Wed, 29 Mar 2017 11:53:00 -0700 Subject: [PATCH 08/19] debugging --- pom.xml | 8 +++--- .../InterviewEvaluationsApplication.java | 1 + .../revature/model/security/Authority.java | 6 ++--- .../com/revature/model/security/User.java | 26 +++++++++---------- .../security/JwtAuthenticationEntryPoint.java | 7 ++++- .../security/JwtAuthenticationFilter.java | 2 +- .../com/revature/security/JwtTokenUtil.java | 2 +- .../security/repository/UserRepository.java | 5 ++++ .../service/JwtUserDetailsServiceImpl.java | 5 ++++ 9 files changed, 39 insertions(+), 23 deletions(-) diff --git a/pom.xml b/pom.xml index 2b2e740..ad40f09 100644 --- a/pom.xml +++ b/pom.xml @@ -75,10 +75,6 @@ - - org.springframework.boot - spring-boot-starter-web - org.springframework.boot spring-boot-starter-test @@ -167,6 +163,10 @@ JBoss Maven Release Repository https://repository.jboss.org/nexus/content/repositories/releases + + + + diff --git a/src/main/java/com/revature/InterviewEvaluationsApplication.java b/src/main/java/com/revature/InterviewEvaluationsApplication.java index 406a464..cc871b0 100644 --- a/src/main/java/com/revature/InterviewEvaluationsApplication.java +++ b/src/main/java/com/revature/InterviewEvaluationsApplication.java @@ -11,6 +11,7 @@ public class InterviewEvaluationsApplication { public static void main(String[] args) { + SpringApplication.run(InterviewEvaluationsApplication.class, args); } diff --git a/src/main/java/com/revature/model/security/Authority.java b/src/main/java/com/revature/model/security/Authority.java index 0a8f825..2242867 100644 --- a/src/main/java/com/revature/model/security/Authority.java +++ b/src/main/java/com/revature/model/security/Authority.java @@ -19,16 +19,16 @@ */ @Entity -@Table(name = "AUTHORITY") +@Table(name = "ie_AUTHORITY") public class Authority { @Id - @Column(name = "ID") + @Column(name = "a_authID") @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "authority_seq") @SequenceGenerator(name = "authority_seq", sequenceName = "authority_seq", allocationSize = 1) private Long id; - @Column(name = "NAME", length = 50) + @Column(name = "a_authorityName", length = 50) @NotNull @Enumerated(EnumType.STRING) private AuthorityName name; diff --git a/src/main/java/com/revature/model/security/User.java b/src/main/java/com/revature/model/security/User.java index d1dc7f1..26617f6 100644 --- a/src/main/java/com/revature/model/security/User.java +++ b/src/main/java/com/revature/model/security/User.java @@ -34,54 +34,54 @@ */ @Entity -@Table(name = "USER") +@Table(name = "ie_user") public class User { @Id - @Column(name = "ID") + @Column(name = "u_userID") @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_seq") @SequenceGenerator(name = "user_seq", sequenceName = "user_seq", allocationSize = 1) private Long id; - @Column(name = "USERNAME", length = 50, unique = true) + @Column(name = "u_username", length = 50, unique = true) @NotNull @Size(min = 4, max = 50) private String username; - @Column(name = "PASSWORD", length = 100) + @Column(name = "u_password", length = 100) @NotNull @Size(min = 4, max = 100) private String password; - @Column(name = "FIRSTNAME", length = 50) + @Column(name = "u_firstName", length = 50) @NotNull @Size(min = 4, max = 50) private String firstname; - @Column(name = "LASTNAME", length = 50) + @Column(name = "u_lastName", length = 50) @NotNull @Size(min = 4, max = 50) private String lastname; - @Column(name = "EMAIL", length = 50) + @Column(name = "u_email", length = 50) @NotNull @Size(min = 4, max = 50) private String email; - @Column(name = "ENABLED") + @Column(name = "u_enabled") @NotNull private Boolean enabled; - @Column(name = "LASTPASSWORDRESETDATE") + @Column(name = "u_lastpasswordresetdate") @Temporal(TemporalType.TIMESTAMP) @NotNull private Date lastPasswordResetDate; @ManyToMany(fetch = FetchType.EAGER) @JoinTable( - name = "USER_AUTHORITY", - joinColumns = {@JoinColumn(name = "USER_ID", referencedColumnName = "ID")}, - inverseJoinColumns = {@JoinColumn(name = "AUTHORITY_ID", referencedColumnName = "ID")}) + name = "ua_user_authority", + joinColumns = {@JoinColumn(name = "u_user_id", referencedColumnName = "u_userID")}, + inverseJoinColumns = {@JoinColumn(name = "a_authority_id", referencedColumnName = "a_authID")}) private List authorities; public Long getId() { @@ -154,5 +154,5 @@ public Date getLastPasswordResetDate() { public void setLastPasswordResetDate(Date lastPasswordResetDate) { this.lastPasswordResetDate = lastPasswordResetDate; - } + } } diff --git a/src/main/java/com/revature/security/JwtAuthenticationEntryPoint.java b/src/main/java/com/revature/security/JwtAuthenticationEntryPoint.java index bd1f293..6a73638 100644 --- a/src/main/java/com/revature/security/JwtAuthenticationEntryPoint.java +++ b/src/main/java/com/revature/security/JwtAuthenticationEntryPoint.java @@ -6,17 +6,22 @@ package com.revature.security; import java.io.IOException; +import java.io.Serializable; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; /** * * @author FayeRedd */ -public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint{ +@Component +public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable{ + private static final long serialVersionUID = -8970718410437077606L; + @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException { response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); diff --git a/src/main/java/com/revature/security/JwtAuthenticationFilter.java b/src/main/java/com/revature/security/JwtAuthenticationFilter.java index 8298cb7..2e20554 100644 --- a/src/main/java/com/revature/security/JwtAuthenticationFilter.java +++ b/src/main/java/com/revature/security/JwtAuthenticationFilter.java @@ -32,7 +32,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { @Autowired private UserDetailsService userDetailsService; - //This is the token generator. Can be replaced with future microservice providing/varifying tokens + //This is the token generator/validator. Can be replaced with future microservice providing/varifying tokens @Autowired private JwtTokenUtil jwtTokenUtil; diff --git a/src/main/java/com/revature/security/JwtTokenUtil.java b/src/main/java/com/revature/security/JwtTokenUtil.java index 221960f..e7522fd 100644 --- a/src/main/java/com/revature/security/JwtTokenUtil.java +++ b/src/main/java/com/revature/security/JwtTokenUtil.java @@ -9,7 +9,7 @@ * * @author FayeRedd */ -import com.revature.security.JwtUser; + import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; diff --git a/src/main/java/com/revature/security/repository/UserRepository.java b/src/main/java/com/revature/security/repository/UserRepository.java index 2fe4d2d..cb3b0e1 100644 --- a/src/main/java/com/revature/security/repository/UserRepository.java +++ b/src/main/java/com/revature/security/repository/UserRepository.java @@ -7,11 +7,16 @@ import com.revature.model.security.User; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; /** * * @author FayeRedd */ + +@Repository public interface UserRepository extends JpaRepository { + User findByUsername(String username); + } diff --git a/src/main/java/com/revature/security/service/JwtUserDetailsServiceImpl.java b/src/main/java/com/revature/security/service/JwtUserDetailsServiceImpl.java index 7f4128c..928d755 100644 --- a/src/main/java/com/revature/security/service/JwtUserDetailsServiceImpl.java +++ b/src/main/java/com/revature/security/service/JwtUserDetailsServiceImpl.java @@ -34,4 +34,9 @@ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundEx return JwtUserFactory.create(user); } } + +// @Override +// public UserDetails loadUserByUsername(String string) throws UsernameNotFoundException { +// throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. +// } } \ No newline at end of file From c9770fe8130e70ef254563f9339b43007fae8335 Mon Sep 17 00:00:00 2001 From: Madison Date: Wed, 29 Mar 2017 12:21:49 -0700 Subject: [PATCH 09/19] bugfix --- .../java/com/revature/InterviewEvaluationsApplication.java | 2 +- .../{security/repository => repositories}/UserRepository.java | 3 ++- .../revature/security/service/JwtUserDetailsServiceImpl.java | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) rename src/main/java/com/revature/{security/repository => repositories}/UserRepository.java (92%) diff --git a/src/main/java/com/revature/InterviewEvaluationsApplication.java b/src/main/java/com/revature/InterviewEvaluationsApplication.java index cc871b0..5b74add 100644 --- a/src/main/java/com/revature/InterviewEvaluationsApplication.java +++ b/src/main/java/com/revature/InterviewEvaluationsApplication.java @@ -11,7 +11,7 @@ public class InterviewEvaluationsApplication { public static void main(String[] args) { - + SpringApplication.run(InterviewEvaluationsApplication.class, args); } diff --git a/src/main/java/com/revature/security/repository/UserRepository.java b/src/main/java/com/revature/repositories/UserRepository.java similarity index 92% rename from src/main/java/com/revature/security/repository/UserRepository.java rename to src/main/java/com/revature/repositories/UserRepository.java index cb3b0e1..26dd61f 100644 --- a/src/main/java/com/revature/security/repository/UserRepository.java +++ b/src/main/java/com/revature/repositories/UserRepository.java @@ -3,7 +3,7 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package com.revature.security.repository; +package com.revature.repositories; import com.revature.model.security.User; import org.springframework.data.jpa.repository.JpaRepository; @@ -14,6 +14,7 @@ * @author FayeRedd */ + @Repository public interface UserRepository extends JpaRepository { diff --git a/src/main/java/com/revature/security/service/JwtUserDetailsServiceImpl.java b/src/main/java/com/revature/security/service/JwtUserDetailsServiceImpl.java index 928d755..7a4ae59 100644 --- a/src/main/java/com/revature/security/service/JwtUserDetailsServiceImpl.java +++ b/src/main/java/com/revature/security/service/JwtUserDetailsServiceImpl.java @@ -7,7 +7,7 @@ import com.revature.model.security.User; import com.revature.security.JwtUserFactory; -import com.revature.security.repository.UserRepository; +import com.revature.repositories.UserRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; From cb0606c97290433c40221ef4705b373b966ba6ac Mon Sep 17 00:00:00 2001 From: Madison Date: Wed, 29 Mar 2017 16:42:54 -0700 Subject: [PATCH 10/19] security tested, operational --- .../security/JwtAuthenticationFilter.java | 10 ++-- .../com/revature/security/JwtTokenTest.java | 48 +++++++++++++++++++ 2 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 src/test/java/com/revature/security/JwtTokenTest.java diff --git a/src/main/java/com/revature/security/JwtAuthenticationFilter.java b/src/main/java/com/revature/security/JwtAuthenticationFilter.java index 2e20554..b7f0917 100644 --- a/src/main/java/com/revature/security/JwtAuthenticationFilter.java +++ b/src/main/java/com/revature/security/JwtAuthenticationFilter.java @@ -10,8 +10,8 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +//import org.apache.commons.logging.Log; +//import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; @@ -27,7 +27,7 @@ */ public class JwtAuthenticationFilter extends OncePerRequestFilter { - private final Log logger = LogFactory.getLog(this.getClass()); + // private final Log myLogger = LogFactory.getLog(this.getClass()); @Autowired private UserDetailsService userDetailsService; @@ -45,7 +45,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse String username = jwtTokenUtil.getUsernameFromToken(authToken); - logger.info("checking authentication for das user " + username); + // myLogger.info("checking authentication for das user " + username); if(username != null && SecurityContextHolder.getContext().getAuthentication() == null){ UserDetails userDetails = this.userDetailsService.loadUserByUsername(username); @@ -55,7 +55,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); - logger.info("authenticated user " + username + ", setting security context"); + // myLogger.info("authenticated user " + username + ", setting security context"); SecurityContextHolder.getContext().setAuthentication(authentication); } diff --git a/src/test/java/com/revature/security/JwtTokenTest.java b/src/test/java/com/revature/security/JwtTokenTest.java new file mode 100644 index 0000000..5aaf2ef --- /dev/null +++ b/src/test/java/com/revature/security/JwtTokenTest.java @@ -0,0 +1,48 @@ +/* + * The MIT License + * + */ +package com.revature.security; + +import java.util.HashMap; +import java.util.Map; +import org.assertj.core.util.DateUtil; +import static org.assertj.core.api.Assertions.assertThat; +import org.junit.Before; +import org.junit.Test; +import org.springframework.test.util.ReflectionTestUtils; + +/** + * + * @author FayeRedd + */ +public class JwtTokenTest { + private JwtTokenUtil jwtTokenUtil; + + @Before + public void init() { + jwtTokenUtil = new JwtTokenUtil(); + ReflectionTestUtils.setField(jwtTokenUtil, "expiration", 3600000L); + ReflectionTestUtils.setField(jwtTokenUtil, "secret", "mySecret"); + } + + @Test + public void testGenerateTokenGeneratesDifferentTokensForDifferentCreationDates() throws Exception { + final Map claims = createClaims("2016-09-08T03:00:00"); + final String token = jwtTokenUtil.generateToken(claims); + + final Map claimsForLaterToken = createClaims("2016-09-08T08:00:00"); + final String laterToken = jwtTokenUtil.generateToken(claimsForLaterToken); + + assertThat(token).isNotEqualTo(laterToken); + } + + private Map createClaims(String creationDate) { + Map claims = new HashMap(); + claims.put(JwtTokenUtil.CLAIM_KEY_USERNAME, "testUser"); + claims.put(JwtTokenUtil.CLAIM_KEY_AUDIENCE, "testAudience"); + claims.put(JwtTokenUtil.CLAIM_KEY_CREATED, DateUtil.parseDatetime(creationDate)); + return claims; + } + +} From cb4a1914630b47f1640af3d7fa85182029300ed5 Mon Sep 17 00:00:00 2001 From: Madison Date: Thu, 30 Mar 2017 09:32:53 -0700 Subject: [PATCH 11/19] code clean --- .../revature/config/WebSecurityConfig.java | 2 +- .../security/JwtAuthenticationFilter.java | 8 ------- .../JwtAuthenticationSuccessHandler.java | 24 ------------------- .../com/revature/security/JwtTokenUtil.java | 22 +++++++++++------ .../service/JwtUserDetailsServiceImpl.java | 5 ---- 5 files changed, 16 insertions(+), 45 deletions(-) delete mode 100644 src/main/java/com/revature/security/JwtAuthenticationSuccessHandler.java diff --git a/src/main/java/com/revature/config/WebSecurityConfig.java b/src/main/java/com/revature/config/WebSecurityConfig.java index b970f06..afcd4f8 100644 --- a/src/main/java/com/revature/config/WebSecurityConfig.java +++ b/src/main/java/com/revature/config/WebSecurityConfig.java @@ -52,7 +52,7 @@ public PasswordEncoder passwordEncoder() { } @Bean - public JwtAuthenticationFilter authenticationFilterBean() throws Exception { + public JwtAuthenticationFilter authenticationFilterBean(){ return new JwtAuthenticationFilter(); } diff --git a/src/main/java/com/revature/security/JwtAuthenticationFilter.java b/src/main/java/com/revature/security/JwtAuthenticationFilter.java index b7f0917..a6f175d 100644 --- a/src/main/java/com/revature/security/JwtAuthenticationFilter.java +++ b/src/main/java/com/revature/security/JwtAuthenticationFilter.java @@ -10,8 +10,6 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -//import org.apache.commons.logging.Log; -//import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; @@ -26,8 +24,6 @@ * @author FayeRedd */ public class JwtAuthenticationFilter extends OncePerRequestFilter { - - // private final Log myLogger = LogFactory.getLog(this.getClass()); @Autowired private UserDetailsService userDetailsService; @@ -45,8 +41,6 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse String username = jwtTokenUtil.getUsernameFromToken(authToken); - // myLogger.info("checking authentication for das user " + username); - if(username != null && SecurityContextHolder.getContext().getAuthentication() == null){ UserDetails userDetails = this.userDetailsService.loadUserByUsername(username); @@ -55,8 +49,6 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); - // myLogger.info("authenticated user " + username + ", setting security context"); - SecurityContextHolder.getContext().setAuthentication(authentication); } } diff --git a/src/main/java/com/revature/security/JwtAuthenticationSuccessHandler.java b/src/main/java/com/revature/security/JwtAuthenticationSuccessHandler.java deleted file mode 100644 index a7ee1e2..0000000 --- a/src/main/java/com/revature/security/JwtAuthenticationSuccessHandler.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package com.revature.security; - -import java.io.IOException; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.springframework.security.core.Authentication; -import org.springframework.security.web.authentication.AuthenticationSuccessHandler; - -/** - * - * @author FayeRedd - */ -public class JwtAuthenticationSuccessHandler implements AuthenticationSuccessHandler{ - - @Override - public void onAuthenticationSuccess(HttpServletRequest hsr, HttpServletResponse hsr1, Authentication a) throws IOException, ServletException {} - -} diff --git a/src/main/java/com/revature/security/JwtTokenUtil.java b/src/main/java/com/revature/security/JwtTokenUtil.java index e7522fd..6543f72 100644 --- a/src/main/java/com/revature/security/JwtTokenUtil.java +++ b/src/main/java/com/revature/security/JwtTokenUtil.java @@ -10,9 +10,14 @@ * @author FayeRedd */ +import com.sun.istack.internal.Nullable; import io.jsonwebtoken.Claims; +import io.jsonwebtoken.ExpiredJwtException; import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.MalformedJwtException; import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.SignatureException; +import io.jsonwebtoken.UnsupportedJwtException; import org.springframework.beans.factory.annotation.Value; import org.springframework.mobile.device.Device; import org.springframework.security.core.userdetails.UserDetails; @@ -50,6 +55,7 @@ public class JwtTokenUtil implements Serializable { @Value("${jwt.expiration}") private Long expiration; + @Nullable public String getUsernameFromToken(String token) { String username; try { @@ -61,6 +67,7 @@ public String getUsernameFromToken(String token) { return username; } + @Nullable public Date getCreatedDateFromToken(String token) { Date created; try { @@ -72,6 +79,7 @@ public Date getCreatedDateFromToken(String token) { return created; } + @Nullable public Date getExpirationDateFromToken(String token) { Date expires; try { @@ -83,6 +91,7 @@ public Date getExpirationDateFromToken(String token) { return expires; } + @Nullable public String getAudienceFromToken(String token) { String audience; try { @@ -101,7 +110,7 @@ private Claims getClaimsFromToken(String token) { .setSigningKey(secret) .parseClaimsJws(token) .getBody(); - } catch (Exception e) { + } catch (ExpiredJwtException | MalformedJwtException | SignatureException | UnsupportedJwtException | IllegalArgumentException e) { claims = null; } return claims; @@ -117,7 +126,7 @@ private Boolean isTokenExpired(String token) { } private Boolean isCreatedBeforeLastPasswordReset(Date created, Date lastPasswordReset) { - return (lastPasswordReset != null && created.before(lastPasswordReset)); + return lastPasswordReset != null && created.before(lastPasswordReset); } private String generateAudience(Device device) { @@ -134,7 +143,7 @@ private String generateAudience(Device device) { private Boolean ignoreTokenExpiration(String token) { String audience = getAudienceFromToken(token); - return (AUDIENCE_TABLET.equals(audience) || AUDIENCE_MOBILE.equals(audience)); + return AUDIENCE_TABLET.equals(audience) || AUDIENCE_MOBILE.equals(audience); } public String generateToken(UserDetails userDetails, Device device) { @@ -159,6 +168,7 @@ public Boolean canTokenBeRefreshed(String token, Date lastPasswordReset) { && (!isTokenExpired(token) || ignoreTokenExpiration(token)); } + @Nullable public String refreshToken(String token) { String refreshedToken; try { @@ -175,10 +185,8 @@ public Boolean validateToken(String token, UserDetails userDetails) { JwtUser user = (JwtUser) userDetails; final String username = getUsernameFromToken(token); final Date created = getCreatedDateFromToken(token); - //final Date expiration = getExpirationDateFromToken(token); - return ( - username.equals(user.getUsername()) + return username.equals(user.getUsername()) && !isTokenExpired(token) - && !isCreatedBeforeLastPasswordReset(created, user.getLastPasswordResetDate())); + && !isCreatedBeforeLastPasswordReset(created, user.getLastPasswordResetDate()); } } \ No newline at end of file diff --git a/src/main/java/com/revature/security/service/JwtUserDetailsServiceImpl.java b/src/main/java/com/revature/security/service/JwtUserDetailsServiceImpl.java index 7a4ae59..a61c1c0 100644 --- a/src/main/java/com/revature/security/service/JwtUserDetailsServiceImpl.java +++ b/src/main/java/com/revature/security/service/JwtUserDetailsServiceImpl.java @@ -34,9 +34,4 @@ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundEx return JwtUserFactory.create(user); } } - -// @Override -// public UserDetails loadUserByUsername(String string) throws UsernameNotFoundException { -// throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. -// } } \ No newline at end of file From 5825af0c858167337f0a2c8fc315967ad83c0e40 Mon Sep 17 00:00:00 2001 From: Madison Date: Thu, 30 Mar 2017 09:39:31 -0700 Subject: [PATCH 12/19] bugfix --- src/main/java/com/revature/security/JwtTokenUtil.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/main/java/com/revature/security/JwtTokenUtil.java b/src/main/java/com/revature/security/JwtTokenUtil.java index 6543f72..e43b416 100644 --- a/src/main/java/com/revature/security/JwtTokenUtil.java +++ b/src/main/java/com/revature/security/JwtTokenUtil.java @@ -10,7 +10,6 @@ * @author FayeRedd */ -import com.sun.istack.internal.Nullable; import io.jsonwebtoken.Claims; import io.jsonwebtoken.ExpiredJwtException; import io.jsonwebtoken.Jwts; @@ -55,7 +54,6 @@ public class JwtTokenUtil implements Serializable { @Value("${jwt.expiration}") private Long expiration; - @Nullable public String getUsernameFromToken(String token) { String username; try { @@ -67,7 +65,6 @@ public String getUsernameFromToken(String token) { return username; } - @Nullable public Date getCreatedDateFromToken(String token) { Date created; try { @@ -79,7 +76,6 @@ public Date getCreatedDateFromToken(String token) { return created; } - @Nullable public Date getExpirationDateFromToken(String token) { Date expires; try { @@ -91,7 +87,6 @@ public Date getExpirationDateFromToken(String token) { return expires; } - @Nullable public String getAudienceFromToken(String token) { String audience; try { @@ -168,7 +163,6 @@ public Boolean canTokenBeRefreshed(String token, Date lastPasswordReset) { && (!isTokenExpired(token) || ignoreTokenExpiration(token)); } - @Nullable public String refreshToken(String token) { String refreshedToken; try { From 76d4c6f069511aa5fea2d467cc0390c7612899ba Mon Sep 17 00:00:00 2001 From: Madison Date: Thu, 30 Mar 2017 09:47:35 -0700 Subject: [PATCH 13/19] code clean --- src/main/java/com/revature/config/WebSecurityConfig.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/main/java/com/revature/config/WebSecurityConfig.java b/src/main/java/com/revature/config/WebSecurityConfig.java index afcd4f8..9cb84ed 100644 --- a/src/main/java/com/revature/config/WebSecurityConfig.java +++ b/src/main/java/com/revature/config/WebSecurityConfig.java @@ -60,17 +60,11 @@ public JwtAuthenticationFilter authenticationFilterBean(){ protected void configure(HttpSecurity httpSecurity) throws Exception{ httpSecurity .csrf().disable() - .exceptionHandling().authenticationEntryPoint(unauthorizedHandler) - .and() - .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) - .and() - .authorizeRequests() - .antMatchers( HttpMethod.GET, "/", From 8569e907bfc28ba579737b14b4287006cbb085b6 Mon Sep 17 00:00:00 2001 From: Madison Date: Fri, 31 Mar 2017 09:37:51 -0700 Subject: [PATCH 14/19] refactored security into core and extra; core to remain with the API, extra to be discarded when external token generation/validation is implemented --- .../java/com/revature/config/WebSecurityConfig.java | 4 ++-- .../{ => core}/JwtAuthenticationEntryPoint.java | 2 +- .../{ => core}/JwtAuthenticationFilter.java | 3 ++- .../{ => core}/JwtAuthenticationRequest.java | 2 +- .../com/revature/security/{ => core}/JwtUser.java | 2 +- .../security/{ => core}/JwtUserFactory.java | 6 +++--- .../exceptions/JwtTokenMissingException.java | 2 +- .../services}/JwtAuthenticationResponse.java | 2 +- .../services}/JwtUserDetailsServiceImpl.java | 13 +++++++++---- .../AuthenticationRestController.java | 10 +++++----- .../security => security/extra}/Authority.java | 2 +- .../security => security/extra}/AuthorityName.java | 2 +- .../revature/security/{ => extra}/JwtTokenUtil.java | 3 ++- .../{model/security => security/extra}/User.java | 2 +- .../extra}/UserRepository.java | 5 ++--- .../{controllers => extra}/UserRestController.java | 6 +++--- .../java/com/revature/security/JwtTokenTest.java | 1 + 17 files changed, 37 insertions(+), 30 deletions(-) rename src/main/java/com/revature/security/{ => core}/JwtAuthenticationEntryPoint.java (96%) rename src/main/java/com/revature/security/{ => core}/JwtAuthenticationFilter.java (96%) rename src/main/java/com/revature/security/{ => core}/JwtAuthenticationRequest.java (96%) rename src/main/java/com/revature/security/{ => core}/JwtUser.java (98%) rename src/main/java/com/revature/security/{ => core}/JwtUserFactory.java (90%) rename src/main/java/com/revature/security/{ => core}/exceptions/JwtTokenMissingException.java (89%) rename src/main/java/com/revature/security/{service => core/services}/JwtAuthenticationResponse.java (92%) rename src/main/java/com/revature/security/{service => core/services}/JwtUserDetailsServiceImpl.java (70%) rename src/main/java/com/revature/security/{controllers => extra}/AuthenticationRestController.java (92%) rename src/main/java/com/revature/{model/security => security/extra}/Authority.java (97%) rename src/main/java/com/revature/{model/security => security/extra}/AuthorityName.java (88%) rename src/main/java/com/revature/security/{ => extra}/JwtTokenUtil.java (98%) rename src/main/java/com/revature/{model/security => security/extra}/User.java (99%) rename src/main/java/com/revature/{repositories => security/extra}/UserRepository.java (85%) rename src/main/java/com/revature/security/{controllers => extra}/UserRestController.java (91%) diff --git a/src/main/java/com/revature/config/WebSecurityConfig.java b/src/main/java/com/revature/config/WebSecurityConfig.java index 9cb84ed..995de8f 100644 --- a/src/main/java/com/revature/config/WebSecurityConfig.java +++ b/src/main/java/com/revature/config/WebSecurityConfig.java @@ -5,8 +5,8 @@ */ package com.revature.config; -import com.revature.security.JwtAuthenticationEntryPoint; -import com.revature.security.JwtAuthenticationFilter; +import com.revature.security.core.JwtAuthenticationEntryPoint; +import com.revature.security.core.JwtAuthenticationFilter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/src/main/java/com/revature/security/JwtAuthenticationEntryPoint.java b/src/main/java/com/revature/security/core/JwtAuthenticationEntryPoint.java similarity index 96% rename from src/main/java/com/revature/security/JwtAuthenticationEntryPoint.java rename to src/main/java/com/revature/security/core/JwtAuthenticationEntryPoint.java index 6a73638..d79acd5 100644 --- a/src/main/java/com/revature/security/JwtAuthenticationEntryPoint.java +++ b/src/main/java/com/revature/security/core/JwtAuthenticationEntryPoint.java @@ -3,7 +3,7 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package com.revature.security; +package com.revature.security.core; import java.io.IOException; import java.io.Serializable; diff --git a/src/main/java/com/revature/security/JwtAuthenticationFilter.java b/src/main/java/com/revature/security/core/JwtAuthenticationFilter.java similarity index 96% rename from src/main/java/com/revature/security/JwtAuthenticationFilter.java rename to src/main/java/com/revature/security/core/JwtAuthenticationFilter.java index a6f175d..315adb7 100644 --- a/src/main/java/com/revature/security/JwtAuthenticationFilter.java +++ b/src/main/java/com/revature/security/core/JwtAuthenticationFilter.java @@ -3,8 +3,9 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package com.revature.security; +package com.revature.security.core; +import com.revature.security.extra.JwtTokenUtil; import java.io.IOException; import javax.servlet.FilterChain; import javax.servlet.ServletException; diff --git a/src/main/java/com/revature/security/JwtAuthenticationRequest.java b/src/main/java/com/revature/security/core/JwtAuthenticationRequest.java similarity index 96% rename from src/main/java/com/revature/security/JwtAuthenticationRequest.java rename to src/main/java/com/revature/security/core/JwtAuthenticationRequest.java index c6555c9..a6f9cbe 100644 --- a/src/main/java/com/revature/security/JwtAuthenticationRequest.java +++ b/src/main/java/com/revature/security/core/JwtAuthenticationRequest.java @@ -3,7 +3,7 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package com.revature.security; +package com.revature.security.core; import java.io.Serializable; diff --git a/src/main/java/com/revature/security/JwtUser.java b/src/main/java/com/revature/security/core/JwtUser.java similarity index 98% rename from src/main/java/com/revature/security/JwtUser.java rename to src/main/java/com/revature/security/core/JwtUser.java index 6f15b77..cf99b24 100644 --- a/src/main/java/com/revature/security/JwtUser.java +++ b/src/main/java/com/revature/security/core/JwtUser.java @@ -3,7 +3,7 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package com.revature.security; +package com.revature.security.core; /** * diff --git a/src/main/java/com/revature/security/JwtUserFactory.java b/src/main/java/com/revature/security/core/JwtUserFactory.java similarity index 90% rename from src/main/java/com/revature/security/JwtUserFactory.java rename to src/main/java/com/revature/security/core/JwtUserFactory.java index 4bdd5b4..c57108b 100644 --- a/src/main/java/com/revature/security/JwtUserFactory.java +++ b/src/main/java/com/revature/security/core/JwtUserFactory.java @@ -3,10 +3,10 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package com.revature.security; +package com.revature.security.core; -import com.revature.model.security.Authority; -import com.revature.model.security.User; +import com.revature.security.extra.Authority; +import com.revature.security.extra.User; import java.util.List; import java.util.stream.Collectors; import org.springframework.security.core.GrantedAuthority; diff --git a/src/main/java/com/revature/security/exceptions/JwtTokenMissingException.java b/src/main/java/com/revature/security/core/exceptions/JwtTokenMissingException.java similarity index 89% rename from src/main/java/com/revature/security/exceptions/JwtTokenMissingException.java rename to src/main/java/com/revature/security/core/exceptions/JwtTokenMissingException.java index 6c2a485..062fb25 100644 --- a/src/main/java/com/revature/security/exceptions/JwtTokenMissingException.java +++ b/src/main/java/com/revature/security/core/exceptions/JwtTokenMissingException.java @@ -3,7 +3,7 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package com.revature.security.exceptions; +package com.revature.security.core.exceptions; /** * diff --git a/src/main/java/com/revature/security/service/JwtAuthenticationResponse.java b/src/main/java/com/revature/security/core/services/JwtAuthenticationResponse.java similarity index 92% rename from src/main/java/com/revature/security/service/JwtAuthenticationResponse.java rename to src/main/java/com/revature/security/core/services/JwtAuthenticationResponse.java index 784f40c..89b1fb9 100644 --- a/src/main/java/com/revature/security/service/JwtAuthenticationResponse.java +++ b/src/main/java/com/revature/security/core/services/JwtAuthenticationResponse.java @@ -3,7 +3,7 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package com.revature.security.service; +package com.revature.security.core.services; import java.io.Serializable; diff --git a/src/main/java/com/revature/security/service/JwtUserDetailsServiceImpl.java b/src/main/java/com/revature/security/core/services/JwtUserDetailsServiceImpl.java similarity index 70% rename from src/main/java/com/revature/security/service/JwtUserDetailsServiceImpl.java rename to src/main/java/com/revature/security/core/services/JwtUserDetailsServiceImpl.java index a61c1c0..bcbcf57 100644 --- a/src/main/java/com/revature/security/service/JwtUserDetailsServiceImpl.java +++ b/src/main/java/com/revature/security/core/services/JwtUserDetailsServiceImpl.java @@ -3,11 +3,11 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package com.revature.security.service; +package com.revature.security.core.services; -import com.revature.model.security.User; -import com.revature.security.JwtUserFactory; -import com.revature.repositories.UserRepository; +import com.revature.security.extra.User; +import com.revature.security.core.JwtUserFactory; +import com.revature.security.extra.UserRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; @@ -34,4 +34,9 @@ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundEx return JwtUserFactory.create(user); } } + +// @Override +// public UserDetails loadUserByUsername(String string) throws UsernameNotFoundException { +// throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. +// } } \ No newline at end of file diff --git a/src/main/java/com/revature/security/controllers/AuthenticationRestController.java b/src/main/java/com/revature/security/extra/AuthenticationRestController.java similarity index 92% rename from src/main/java/com/revature/security/controllers/AuthenticationRestController.java rename to src/main/java/com/revature/security/extra/AuthenticationRestController.java index 4c2c468..d186496 100644 --- a/src/main/java/com/revature/security/controllers/AuthenticationRestController.java +++ b/src/main/java/com/revature/security/extra/AuthenticationRestController.java @@ -3,12 +3,12 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package com.revature.security.controllers; +package com.revature.security.extra; -import com.revature.security.JwtAuthenticationRequest; -import com.revature.security.JwtTokenUtil; -import com.revature.security.JwtUser; -import com.revature.security.service.JwtAuthenticationResponse; +import com.revature.security.core.JwtAuthenticationRequest; +import com.revature.security.extra.JwtTokenUtil; +import com.revature.security.core.JwtUser; +import com.revature.security.core.services.JwtAuthenticationResponse; import javax.servlet.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; diff --git a/src/main/java/com/revature/model/security/Authority.java b/src/main/java/com/revature/security/extra/Authority.java similarity index 97% rename from src/main/java/com/revature/model/security/Authority.java rename to src/main/java/com/revature/security/extra/Authority.java index 2242867..e0e7805 100644 --- a/src/main/java/com/revature/model/security/Authority.java +++ b/src/main/java/com/revature/security/extra/Authority.java @@ -3,7 +3,7 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package com.revature.model.security; +package com.revature.security.extra; /** * diff --git a/src/main/java/com/revature/model/security/AuthorityName.java b/src/main/java/com/revature/security/extra/AuthorityName.java similarity index 88% rename from src/main/java/com/revature/model/security/AuthorityName.java rename to src/main/java/com/revature/security/extra/AuthorityName.java index 95d8929..4b44a5a 100644 --- a/src/main/java/com/revature/model/security/AuthorityName.java +++ b/src/main/java/com/revature/security/extra/AuthorityName.java @@ -3,7 +3,7 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package com.revature.model.security; +package com.revature.security.extra; /** * diff --git a/src/main/java/com/revature/security/JwtTokenUtil.java b/src/main/java/com/revature/security/extra/JwtTokenUtil.java similarity index 98% rename from src/main/java/com/revature/security/JwtTokenUtil.java rename to src/main/java/com/revature/security/extra/JwtTokenUtil.java index e43b416..174fe84 100644 --- a/src/main/java/com/revature/security/JwtTokenUtil.java +++ b/src/main/java/com/revature/security/extra/JwtTokenUtil.java @@ -3,13 +3,14 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package com.revature.security; +package com.revature.security.extra; /** * * @author FayeRedd */ +import com.revature.security.core.JwtUser; import io.jsonwebtoken.Claims; import io.jsonwebtoken.ExpiredJwtException; import io.jsonwebtoken.Jwts; diff --git a/src/main/java/com/revature/model/security/User.java b/src/main/java/com/revature/security/extra/User.java similarity index 99% rename from src/main/java/com/revature/model/security/User.java rename to src/main/java/com/revature/security/extra/User.java index 26617f6..09efec2 100644 --- a/src/main/java/com/revature/model/security/User.java +++ b/src/main/java/com/revature/security/extra/User.java @@ -3,7 +3,7 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package com.revature.model.security; +package com.revature.security.extra; /** * diff --git a/src/main/java/com/revature/repositories/UserRepository.java b/src/main/java/com/revature/security/extra/UserRepository.java similarity index 85% rename from src/main/java/com/revature/repositories/UserRepository.java rename to src/main/java/com/revature/security/extra/UserRepository.java index 26dd61f..9d37d02 100644 --- a/src/main/java/com/revature/repositories/UserRepository.java +++ b/src/main/java/com/revature/security/extra/UserRepository.java @@ -3,9 +3,9 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package com.revature.repositories; +package com.revature.security.extra; -import com.revature.model.security.User; +import com.revature.security.extra.User; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @@ -14,7 +14,6 @@ * @author FayeRedd */ - @Repository public interface UserRepository extends JpaRepository { diff --git a/src/main/java/com/revature/security/controllers/UserRestController.java b/src/main/java/com/revature/security/extra/UserRestController.java similarity index 91% rename from src/main/java/com/revature/security/controllers/UserRestController.java rename to src/main/java/com/revature/security/extra/UserRestController.java index d484f86..1fc8cca 100644 --- a/src/main/java/com/revature/security/controllers/UserRestController.java +++ b/src/main/java/com/revature/security/extra/UserRestController.java @@ -3,10 +3,10 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package com.revature.security.controllers; +package com.revature.security.extra; -import com.revature.security.JwtTokenUtil; -import com.revature.security.JwtUser; +import com.revature.security.extra.JwtTokenUtil; +import com.revature.security.core.JwtUser; import javax.servlet.http.HttpServletRequest; diff --git a/src/test/java/com/revature/security/JwtTokenTest.java b/src/test/java/com/revature/security/JwtTokenTest.java index 5aaf2ef..ea986c1 100644 --- a/src/test/java/com/revature/security/JwtTokenTest.java +++ b/src/test/java/com/revature/security/JwtTokenTest.java @@ -4,6 +4,7 @@ */ package com.revature.security; +import com.revature.security.extra.JwtTokenUtil; import java.util.HashMap; import java.util.Map; import org.assertj.core.util.DateUtil; From 673e6c53261096ef8f92accde2b4924db303bd21 Mon Sep 17 00:00:00 2001 From: Madison Date: Fri, 31 Mar 2017 10:07:20 -0700 Subject: [PATCH 15/19] refactored --- .../{security/extra => repositories}/UserRepository.java | 2 +- .../AuthenticationRestController.java | 6 +++--- .../security/{extra => controllers}/UserRestController.java | 4 ++-- .../com/revature/security/core/JwtAuthenticationFilter.java | 5 ++++- src/main/java/com/revature/security/extra/JwtTokenUtil.java | 2 +- .../java/com/revature/security/{core => extra}/JwtUser.java | 2 +- .../revature/security/{core => extra}/JwtUserFactory.java | 2 +- .../com/revature/security/extra/{ => model}/Authority.java | 0 .../revature/security/extra/{ => model}/AuthorityName.java | 0 .../java/com/revature/security/extra/{ => model}/User.java | 0 .../service}/JwtAuthenticationResponse.java | 2 +- .../service}/JwtUserDetailsServiceImpl.java | 6 +++--- .../com/revature/security/{ => extra}/JwtTokenTest.java | 2 +- 13 files changed, 18 insertions(+), 15 deletions(-) rename src/main/java/com/revature/{security/extra => repositories}/UserRepository.java (93%) rename src/main/java/com/revature/security/{extra => controllers}/AuthenticationRestController.java (95%) rename src/main/java/com/revature/security/{extra => controllers}/UserRestController.java (94%) rename src/main/java/com/revature/security/{core => extra}/JwtUser.java (98%) rename src/main/java/com/revature/security/{core => extra}/JwtUserFactory.java (97%) rename src/main/java/com/revature/security/extra/{ => model}/Authority.java (100%) rename src/main/java/com/revature/security/extra/{ => model}/AuthorityName.java (100%) rename src/main/java/com/revature/security/extra/{ => model}/User.java (100%) rename src/main/java/com/revature/security/{core/services => extra/service}/JwtAuthenticationResponse.java (92%) rename src/main/java/com/revature/security/{core/services => extra/service}/JwtUserDetailsServiceImpl.java (90%) rename src/test/java/com/revature/security/{ => extra}/JwtTokenTest.java (97%) diff --git a/src/main/java/com/revature/security/extra/UserRepository.java b/src/main/java/com/revature/repositories/UserRepository.java similarity index 93% rename from src/main/java/com/revature/security/extra/UserRepository.java rename to src/main/java/com/revature/repositories/UserRepository.java index 9d37d02..5df6747 100644 --- a/src/main/java/com/revature/security/extra/UserRepository.java +++ b/src/main/java/com/revature/repositories/UserRepository.java @@ -3,7 +3,7 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package com.revature.security.extra; +package com.revature.repositories; import com.revature.security.extra.User; import org.springframework.data.jpa.repository.JpaRepository; diff --git a/src/main/java/com/revature/security/extra/AuthenticationRestController.java b/src/main/java/com/revature/security/controllers/AuthenticationRestController.java similarity index 95% rename from src/main/java/com/revature/security/extra/AuthenticationRestController.java rename to src/main/java/com/revature/security/controllers/AuthenticationRestController.java index d186496..0229741 100644 --- a/src/main/java/com/revature/security/extra/AuthenticationRestController.java +++ b/src/main/java/com/revature/security/controllers/AuthenticationRestController.java @@ -3,12 +3,12 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package com.revature.security.extra; +package com.revature.security.controllers; import com.revature.security.core.JwtAuthenticationRequest; import com.revature.security.extra.JwtTokenUtil; -import com.revature.security.core.JwtUser; -import com.revature.security.core.services.JwtAuthenticationResponse; +import com.revature.security.extra.JwtUser; +import com.revature.security.extra.JwtAuthenticationResponse; import javax.servlet.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; diff --git a/src/main/java/com/revature/security/extra/UserRestController.java b/src/main/java/com/revature/security/controllers/UserRestController.java similarity index 94% rename from src/main/java/com/revature/security/extra/UserRestController.java rename to src/main/java/com/revature/security/controllers/UserRestController.java index 1fc8cca..f6e4217 100644 --- a/src/main/java/com/revature/security/extra/UserRestController.java +++ b/src/main/java/com/revature/security/controllers/UserRestController.java @@ -3,10 +3,10 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package com.revature.security.extra; +package com.revature.security.controllers; import com.revature.security.extra.JwtTokenUtil; -import com.revature.security.core.JwtUser; +import com.revature.security.extra.JwtUser; import javax.servlet.http.HttpServletRequest; diff --git a/src/main/java/com/revature/security/core/JwtAuthenticationFilter.java b/src/main/java/com/revature/security/core/JwtAuthenticationFilter.java index 315adb7..4dd2907 100644 --- a/src/main/java/com/revature/security/core/JwtAuthenticationFilter.java +++ b/src/main/java/com/revature/security/core/JwtAuthenticationFilter.java @@ -33,7 +33,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { @Autowired private JwtTokenUtil jwtTokenUtil; - @Value("Authorization") + @Value("${jwt.header}") private String tokenHeader; @Override @@ -50,6 +50,9 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + // myLogger.info("authenticated user " + username + ", setting security context"); + + SecurityContextHolder.getContext().setAuthentication(authentication); } } diff --git a/src/main/java/com/revature/security/extra/JwtTokenUtil.java b/src/main/java/com/revature/security/extra/JwtTokenUtil.java index 174fe84..3051cfc 100644 --- a/src/main/java/com/revature/security/extra/JwtTokenUtil.java +++ b/src/main/java/com/revature/security/extra/JwtTokenUtil.java @@ -10,7 +10,7 @@ * @author FayeRedd */ -import com.revature.security.core.JwtUser; +import com.revature.security.extra.JwtUser; import io.jsonwebtoken.Claims; import io.jsonwebtoken.ExpiredJwtException; import io.jsonwebtoken.Jwts; diff --git a/src/main/java/com/revature/security/core/JwtUser.java b/src/main/java/com/revature/security/extra/JwtUser.java similarity index 98% rename from src/main/java/com/revature/security/core/JwtUser.java rename to src/main/java/com/revature/security/extra/JwtUser.java index cf99b24..36c5e62 100644 --- a/src/main/java/com/revature/security/core/JwtUser.java +++ b/src/main/java/com/revature/security/extra/JwtUser.java @@ -3,7 +3,7 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package com.revature.security.core; +package com.revature.security.extra; /** * diff --git a/src/main/java/com/revature/security/core/JwtUserFactory.java b/src/main/java/com/revature/security/extra/JwtUserFactory.java similarity index 97% rename from src/main/java/com/revature/security/core/JwtUserFactory.java rename to src/main/java/com/revature/security/extra/JwtUserFactory.java index c57108b..7b8ace0 100644 --- a/src/main/java/com/revature/security/core/JwtUserFactory.java +++ b/src/main/java/com/revature/security/extra/JwtUserFactory.java @@ -3,7 +3,7 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package com.revature.security.core; +package com.revature.security.extra; import com.revature.security.extra.Authority; import com.revature.security.extra.User; diff --git a/src/main/java/com/revature/security/extra/Authority.java b/src/main/java/com/revature/security/extra/model/Authority.java similarity index 100% rename from src/main/java/com/revature/security/extra/Authority.java rename to src/main/java/com/revature/security/extra/model/Authority.java diff --git a/src/main/java/com/revature/security/extra/AuthorityName.java b/src/main/java/com/revature/security/extra/model/AuthorityName.java similarity index 100% rename from src/main/java/com/revature/security/extra/AuthorityName.java rename to src/main/java/com/revature/security/extra/model/AuthorityName.java diff --git a/src/main/java/com/revature/security/extra/User.java b/src/main/java/com/revature/security/extra/model/User.java similarity index 100% rename from src/main/java/com/revature/security/extra/User.java rename to src/main/java/com/revature/security/extra/model/User.java diff --git a/src/main/java/com/revature/security/core/services/JwtAuthenticationResponse.java b/src/main/java/com/revature/security/extra/service/JwtAuthenticationResponse.java similarity index 92% rename from src/main/java/com/revature/security/core/services/JwtAuthenticationResponse.java rename to src/main/java/com/revature/security/extra/service/JwtAuthenticationResponse.java index 89b1fb9..6c65e7c 100644 --- a/src/main/java/com/revature/security/core/services/JwtAuthenticationResponse.java +++ b/src/main/java/com/revature/security/extra/service/JwtAuthenticationResponse.java @@ -3,7 +3,7 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package com.revature.security.core.services; +package com.revature.security.extra; import java.io.Serializable; diff --git a/src/main/java/com/revature/security/core/services/JwtUserDetailsServiceImpl.java b/src/main/java/com/revature/security/extra/service/JwtUserDetailsServiceImpl.java similarity index 90% rename from src/main/java/com/revature/security/core/services/JwtUserDetailsServiceImpl.java rename to src/main/java/com/revature/security/extra/service/JwtUserDetailsServiceImpl.java index bcbcf57..88179f7 100644 --- a/src/main/java/com/revature/security/core/services/JwtUserDetailsServiceImpl.java +++ b/src/main/java/com/revature/security/extra/service/JwtUserDetailsServiceImpl.java @@ -3,11 +3,11 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package com.revature.security.core.services; +package com.revature.security.extra; import com.revature.security.extra.User; -import com.revature.security.core.JwtUserFactory; -import com.revature.security.extra.UserRepository; +import com.revature.security.extra.JwtUserFactory; +import com.revature.repositories.UserRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; diff --git a/src/test/java/com/revature/security/JwtTokenTest.java b/src/test/java/com/revature/security/extra/JwtTokenTest.java similarity index 97% rename from src/test/java/com/revature/security/JwtTokenTest.java rename to src/test/java/com/revature/security/extra/JwtTokenTest.java index ea986c1..c11ee71 100644 --- a/src/test/java/com/revature/security/JwtTokenTest.java +++ b/src/test/java/com/revature/security/extra/JwtTokenTest.java @@ -2,7 +2,7 @@ * The MIT License * */ -package com.revature.security; +package com.revature.security.extra; import com.revature.security.extra.JwtTokenUtil; import java.util.HashMap; From 4a3ab96b95ff75625393fa771f4f9367cce3a608 Mon Sep 17 00:00:00 2001 From: Madison Date: Wed, 12 Apr 2017 11:28:05 -0700 Subject: [PATCH 16/19] Remove unneeded classes; move login, token generation, token authentication to new project --- pom.xml | 8 + .../revature/config/WebSecurityConfig.java | 2 +- .../revature/repositories/UserRepository.java | 22 --- .../AuthenticationRestController.java | 83 -------- .../controllers/UserRestController.java | 48 ----- .../core/JwtAuthenticationEntryPoint.java | 3 +- .../core/JwtAuthenticationFilter.java | 61 ------ .../core/JwtAuthenticationRequest.java | 45 ----- .../revature/security/extra/JwtTokenUtil.java | 187 ------------------ .../com/revature/security/extra/JwtUser.java | 113 ----------- .../security/extra/JwtUserFactory.java | 45 ----- .../security/extra/model/Authority.java | 62 ------ .../security/extra/model/AuthorityName.java | 14 -- .../revature/security/extra/model/User.java | 158 --------------- .../service/JwtAuthenticationResponse.java | 27 --- .../service/JwtUserDetailsServiceImpl.java | 42 ---- src/main/resources/application.yml | 21 -- .../InterviewEvaluationsApplicationTests.java | 16 -- .../revature/security/extra/JwtTokenTest.java | 49 ----- .../spring/test/PersonEntityTest.java | 0 20 files changed, 10 insertions(+), 996 deletions(-) delete mode 100644 src/main/java/com/revature/repositories/UserRepository.java delete mode 100644 src/main/java/com/revature/security/controllers/AuthenticationRestController.java delete mode 100644 src/main/java/com/revature/security/controllers/UserRestController.java delete mode 100644 src/main/java/com/revature/security/core/JwtAuthenticationFilter.java delete mode 100644 src/main/java/com/revature/security/core/JwtAuthenticationRequest.java delete mode 100644 src/main/java/com/revature/security/extra/JwtTokenUtil.java delete mode 100644 src/main/java/com/revature/security/extra/JwtUser.java delete mode 100644 src/main/java/com/revature/security/extra/JwtUserFactory.java delete mode 100644 src/main/java/com/revature/security/extra/model/Authority.java delete mode 100644 src/main/java/com/revature/security/extra/model/AuthorityName.java delete mode 100644 src/main/java/com/revature/security/extra/model/User.java delete mode 100644 src/main/java/com/revature/security/extra/service/JwtAuthenticationResponse.java delete mode 100644 src/main/java/com/revature/security/extra/service/JwtUserDetailsServiceImpl.java delete mode 100644 src/main/resources/application.yml delete mode 100644 src/test/java/com/revature/InterviewEvaluationsApplicationTests.java delete mode 100644 src/test/java/com/revature/security/extra/JwtTokenTest.java delete mode 100644 src/test/java/com/revature/spring/test/PersonEntityTest.java diff --git a/pom.xml b/pom.xml index ad40f09..edb890b 100644 --- a/pom.xml +++ b/pom.xml @@ -139,6 +139,14 @@ 4.2.1.RELEASE jar + + + + com.revature + RevatureSecurityLogin + 1.0-SNAPSHOT + compile + diff --git a/src/main/java/com/revature/config/WebSecurityConfig.java b/src/main/java/com/revature/config/WebSecurityConfig.java index 995de8f..07cd32b 100644 --- a/src/main/java/com/revature/config/WebSecurityConfig.java +++ b/src/main/java/com/revature/config/WebSecurityConfig.java @@ -6,7 +6,7 @@ package com.revature.config; import com.revature.security.core.JwtAuthenticationEntryPoint; -import com.revature.security.core.JwtAuthenticationFilter; +import com.revature.security.JwtAuthenticationFilter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/src/main/java/com/revature/repositories/UserRepository.java b/src/main/java/com/revature/repositories/UserRepository.java deleted file mode 100644 index 5df6747..0000000 --- a/src/main/java/com/revature/repositories/UserRepository.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package com.revature.repositories; - -import com.revature.security.extra.User; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -/** - * - * @author FayeRedd - */ - -@Repository -public interface UserRepository extends JpaRepository { - - User findByUsername(String username); - -} diff --git a/src/main/java/com/revature/security/controllers/AuthenticationRestController.java b/src/main/java/com/revature/security/controllers/AuthenticationRestController.java deleted file mode 100644 index 0229741..0000000 --- a/src/main/java/com/revature/security/controllers/AuthenticationRestController.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package com.revature.security.controllers; - -import com.revature.security.core.JwtAuthenticationRequest; -import com.revature.security.extra.JwtTokenUtil; -import com.revature.security.extra.JwtUser; -import com.revature.security.extra.JwtAuthenticationResponse; -import javax.servlet.http.HttpServletRequest; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.ResponseEntity; -import org.springframework.mobile.device.Device; -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.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.security.core.userdetails.UserDetails; - -/** - * - * @author FayeRedd - */ - -@RestController -public class AuthenticationRestController { - - //This value can be found in the application.yml file - @Value("${jwt.header}") - private String tokenHeader; - - @Autowired - private AuthenticationManager authMan; - - //This is the token generator/validator. Can be replaced with future microservice providing/varifying tokens - @Autowired - private JwtTokenUtil tokenUtil; - - @Autowired - private UserDetailsService userDetServ; - - //This value can be found in the application.yml file - @RequestMapping(value = "${jwt.route.authentication.path}", method = RequestMethod.POST) - public ResponseEntity createAuthenticationToken(@RequestBody JwtAuthenticationRequest authReq, Device dev) throws AuthenticationException{ - - final Authentication authentication = authMan.authenticate( - new UsernamePasswordAuthenticationToken( - authReq.getUsername(), - authReq.getPassword()) - ); - - SecurityContextHolder.getContext().setAuthentication(authentication); - - final UserDetails userDetails = userDetServ.loadUserByUsername(authReq.getUsername()); - final String token = tokenUtil.generateToken(userDetails, dev); - - return ResponseEntity.ok(new JwtAuthenticationResponse(token)); - } - - //This value can be found in the application.yml file - @RequestMapping(value = "${jwt.route.authentication.refresh}", method = RequestMethod.GET) - public ResponseEntity refreshAndGetAuthenticationToken(HttpServletRequest req){ - String token = req.getHeader(tokenHeader); - String username = tokenUtil.getUsernameFromToken(token); - JwtUser user = (JwtUser) userDetServ.loadUserByUsername(username); - - if(tokenUtil.canTokenBeRefreshed(token, user.getLastPasswordResetDate())){ - String refreshedToken = tokenUtil.refreshToken(token); - return ResponseEntity.ok(new JwtAuthenticationResponse(refreshedToken)); - } else { - return ResponseEntity.badRequest().body(null); - } - } -} diff --git a/src/main/java/com/revature/security/controllers/UserRestController.java b/src/main/java/com/revature/security/controllers/UserRestController.java deleted file mode 100644 index f6e4217..0000000 --- a/src/main/java/com/revature/security/controllers/UserRestController.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package com.revature.security.controllers; - -import com.revature.security.extra.JwtTokenUtil; -import com.revature.security.extra.JwtUser; - -import javax.servlet.http.HttpServletRequest; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; - -/** - * - * @author FayeRedd - */ - -@RestController -public class UserRestController { - - //This value is found in the application.yml file - @Value("${jwt.header}") - private String tokenHeader; - - //This is the token generator/validator. Can be replaced with future microservice providing/varifying tokens - @Autowired - private JwtTokenUtil jwtTokenUtil; - - @Autowired - private UserDetailsService userDetailsService; - - @RequestMapping(value="user", method = RequestMethod.GET) - public JwtUser getAuthenticatedUser(HttpServletRequest req){ - - String token = req.getHeader(tokenHeader); - String username = jwtTokenUtil.getUsernameFromToken(token); - JwtUser user = (JwtUser) userDetailsService.loadUserByUsername(username); - - return user; - } -} \ No newline at end of file diff --git a/src/main/java/com/revature/security/core/JwtAuthenticationEntryPoint.java b/src/main/java/com/revature/security/core/JwtAuthenticationEntryPoint.java index d79acd5..5302f7c 100644 --- a/src/main/java/com/revature/security/core/JwtAuthenticationEntryPoint.java +++ b/src/main/java/com/revature/security/core/JwtAuthenticationEntryPoint.java @@ -25,6 +25,5 @@ public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Se @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException { response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); - } - + } } diff --git a/src/main/java/com/revature/security/core/JwtAuthenticationFilter.java b/src/main/java/com/revature/security/core/JwtAuthenticationFilter.java deleted file mode 100644 index 4dd2907..0000000 --- a/src/main/java/com/revature/security/core/JwtAuthenticationFilter.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package com.revature.security.core; - -import com.revature.security.extra.JwtTokenUtil; -import java.io.IOException; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; -import org.springframework.web.filter.OncePerRequestFilter; - -/** - * - * @author FayeRedd - */ -public class JwtAuthenticationFilter extends OncePerRequestFilter { - - @Autowired - private UserDetailsService userDetailsService; - - //This is the token generator/validator. Can be replaced with future microservice providing/varifying tokens - @Autowired - private JwtTokenUtil jwtTokenUtil; - - @Value("${jwt.header}") - private String tokenHeader; - - @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { - String authToken = request.getHeader(this.tokenHeader); - - String username = jwtTokenUtil.getUsernameFromToken(authToken); - - if(username != null && SecurityContextHolder.getContext().getAuthentication() == null){ - UserDetails userDetails = this.userDetailsService.loadUserByUsername(username); - - if(jwtTokenUtil.validateToken(authToken, userDetails)){ - UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); - - authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); - - // myLogger.info("authenticated user " + username + ", setting security context"); - - - SecurityContextHolder.getContext().setAuthentication(authentication); - } - } - chain.doFilter(request, response); - } -} diff --git a/src/main/java/com/revature/security/core/JwtAuthenticationRequest.java b/src/main/java/com/revature/security/core/JwtAuthenticationRequest.java deleted file mode 100644 index a6f9cbe..0000000 --- a/src/main/java/com/revature/security/core/JwtAuthenticationRequest.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package com.revature.security.core; - -import java.io.Serializable; - -/** - * - * @author FayeRedd - */ -public class JwtAuthenticationRequest implements Serializable { - - private static final long serialVersionUID = -8445943548965154778L; - - private String username; - private String password; - - public JwtAuthenticationRequest() { - super(); - } - - public JwtAuthenticationRequest(String username, String password) { - this.setUsername(username); - this.setPassword(password); - } - - public String getUsername() { - return this.username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getPassword() { - return this.password; - } - - public void setPassword(String password) { - this.password = password; - } -} diff --git a/src/main/java/com/revature/security/extra/JwtTokenUtil.java b/src/main/java/com/revature/security/extra/JwtTokenUtil.java deleted file mode 100644 index 3051cfc..0000000 --- a/src/main/java/com/revature/security/extra/JwtTokenUtil.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package com.revature.security.extra; - -/** - * - * @author FayeRedd - */ - -import com.revature.security.extra.JwtUser; -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.ExpiredJwtException; -import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.MalformedJwtException; -import io.jsonwebtoken.SignatureAlgorithm; -import io.jsonwebtoken.SignatureException; -import io.jsonwebtoken.UnsupportedJwtException; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.mobile.device.Device; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.stereotype.Component; - -import java.io.Serializable; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; - -/* -* This class is the demo token generator/validator. It can be replaced in the future with -* a microservice providing these same features -*/ - -@Component -public class JwtTokenUtil implements Serializable { - - private static final long serialVersionUID = -3301605591108950415L; - - static final String CLAIM_KEY_USERNAME = "sub"; - static final String CLAIM_KEY_AUDIENCE = "audience"; - static final String CLAIM_KEY_CREATED = "created"; - - private static final String AUDIENCE_UNKNOWN = "unknown"; - private static final String AUDIENCE_WEB = "web"; - private static final String AUDIENCE_MOBILE = "mobile"; - private static final String AUDIENCE_TABLET = "tablet"; - - //This value is stored in the application.yml file - @Value("${jwt.secret}") - private String secret; - - //This value is stored in the application.yml file - @Value("${jwt.expiration}") - private Long expiration; - - public String getUsernameFromToken(String token) { - String username; - try { - final Claims claims = getClaimsFromToken(token); - username = claims.getSubject(); - } catch (Exception e) { - username = null; - } - return username; - } - - public Date getCreatedDateFromToken(String token) { - Date created; - try { - final Claims claims = getClaimsFromToken(token); - created = new Date((Long) claims.get(CLAIM_KEY_CREATED)); - } catch (Exception e) { - created = null; - } - return created; - } - - public Date getExpirationDateFromToken(String token) { - Date expires; - try { - final Claims claims = getClaimsFromToken(token); - expires = claims.getExpiration(); - } catch (Exception e) { - expires = null; - } - return expires; - } - - public String getAudienceFromToken(String token) { - String audience; - try { - final Claims claims = getClaimsFromToken(token); - audience = (String) claims.get(CLAIM_KEY_AUDIENCE); - } catch (Exception e) { - audience = null; - } - return audience; - } - - private Claims getClaimsFromToken(String token) { - Claims claims; - try { - claims = Jwts.parser() - .setSigningKey(secret) - .parseClaimsJws(token) - .getBody(); - } catch (ExpiredJwtException | MalformedJwtException | SignatureException | UnsupportedJwtException | IllegalArgumentException e) { - claims = null; - } - return claims; - } - - private Date generateExpirationDate() { - return new Date(System.currentTimeMillis() + expiration * 1000); - } - - private Boolean isTokenExpired(String token) { - final Date expires = getExpirationDateFromToken(token); - return expires.before(new Date()); - } - - private Boolean isCreatedBeforeLastPasswordReset(Date created, Date lastPasswordReset) { - return lastPasswordReset != null && created.before(lastPasswordReset); - } - - private String generateAudience(Device device) { - String audience = AUDIENCE_UNKNOWN; - if (device.isNormal()) { - audience = AUDIENCE_WEB; - } else if (device.isTablet()) { - audience = AUDIENCE_TABLET; - } else if (device.isMobile()) { - audience = AUDIENCE_MOBILE; - } - return audience; - } - - private Boolean ignoreTokenExpiration(String token) { - String audience = getAudienceFromToken(token); - return AUDIENCE_TABLET.equals(audience) || AUDIENCE_MOBILE.equals(audience); - } - - public String generateToken(UserDetails userDetails, Device device) { - Map claims = new HashMap<>(); - claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername()); - claims.put(CLAIM_KEY_AUDIENCE, generateAudience(device)); - claims.put(CLAIM_KEY_CREATED, new Date()); - return generateToken(claims); - } - - String generateToken(Map claims) { - return Jwts.builder() - .setClaims(claims) - .setExpiration(generateExpirationDate()) - .signWith(SignatureAlgorithm.HS512, secret) - .compact(); - } - - public Boolean canTokenBeRefreshed(String token, Date lastPasswordReset) { - final Date created = getCreatedDateFromToken(token); - return !isCreatedBeforeLastPasswordReset(created, lastPasswordReset) - && (!isTokenExpired(token) || ignoreTokenExpiration(token)); - } - - public String refreshToken(String token) { - String refreshedToken; - try { - final Claims claims = getClaimsFromToken(token); - claims.put(CLAIM_KEY_CREATED, new Date()); - refreshedToken = generateToken(claims); - } catch (Exception e) { - refreshedToken = null; - } - return refreshedToken; - } - - public Boolean validateToken(String token, UserDetails userDetails) { - JwtUser user = (JwtUser) userDetails; - final String username = getUsernameFromToken(token); - final Date created = getCreatedDateFromToken(token); - return username.equals(user.getUsername()) - && !isTokenExpired(token) - && !isCreatedBeforeLastPasswordReset(created, user.getLastPasswordResetDate()); - } -} \ No newline at end of file diff --git a/src/main/java/com/revature/security/extra/JwtUser.java b/src/main/java/com/revature/security/extra/JwtUser.java deleted file mode 100644 index 36c5e62..0000000 --- a/src/main/java/com/revature/security/extra/JwtUser.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package com.revature.security.extra; - -/** - * - * @author FayeRedd - */ -import java.util.Collection; -import java.util.Date; - -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.userdetails.UserDetails; - -import com.fasterxml.jackson.annotation.JsonIgnore; - -public class JwtUser implements UserDetails { - - private final Long id; - private final String username; - private final String firstname; - private final String lastname; - private final String password; - private final String email; - private final Collection authorities; - private final boolean enabled; - private final Date lastPasswordResetDate; - - public JwtUser( - Long id, - String username, - String firstname, - String lastname, - String email, - String password, Collection authorities, - boolean enabled, - Date lastPasswordResetDate - ) { - this.id = id; - this.username = username; - this.firstname = firstname; - this.lastname = lastname; - this.email = email; - this.password = password; - this.authorities = authorities; - this.enabled = enabled; - this.lastPasswordResetDate = lastPasswordResetDate; - } - - @JsonIgnore - public Long getId() { - return id; - } - - @Override - public String getUsername() { - return username; - } - - @JsonIgnore - @Override - public boolean isAccountNonExpired() { - return true; - } - - @JsonIgnore - @Override - public boolean isAccountNonLocked() { - return true; - } - - @JsonIgnore - @Override - public boolean isCredentialsNonExpired() { - return true; - } - - public String getFirstname() { - return firstname; - } - - public String getLastname() { - return lastname; - } - - public String getEmail() { - return email; - } - - @JsonIgnore - @Override - public String getPassword() { - return password; - } - - @Override - public Collection getAuthorities() { - return authorities; - } - - @Override - public boolean isEnabled() { - return enabled; - } - - @JsonIgnore - public Date getLastPasswordResetDate() { - return lastPasswordResetDate; - } -} diff --git a/src/main/java/com/revature/security/extra/JwtUserFactory.java b/src/main/java/com/revature/security/extra/JwtUserFactory.java deleted file mode 100644 index 7b8ace0..0000000 --- a/src/main/java/com/revature/security/extra/JwtUserFactory.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package com.revature.security.extra; - -import com.revature.security.extra.Authority; -import com.revature.security.extra.User; -import java.util.List; -import java.util.stream.Collectors; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; - - - -/** - * - * @author FayeRedd - */ -public class JwtUserFactory { - - private JwtUserFactory(){} - - public static JwtUser create(User user){ - return new JwtUser( - user.getId(), - user.getUsername(), - user.getFirstname(), - user.getLastname(), - user.getEmail(), - user.getPassword(), - mapToGrantedAuthorities(user.getAuthorities()), - user.getEnabled(), - user.getLastPasswordResetDate() - ); - } - - private static List mapToGrantedAuthorities(List authorities) { - return authorities.stream() - .map(authority -> new SimpleGrantedAuthority(authority.getName().name())) - .collect(Collectors.toList()); - } - -} diff --git a/src/main/java/com/revature/security/extra/model/Authority.java b/src/main/java/com/revature/security/extra/model/Authority.java deleted file mode 100644 index e0e7805..0000000 --- a/src/main/java/com/revature/security/extra/model/Authority.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package com.revature.security.extra; - -/** - * - * @author FayeRedd - */ -import javax.persistence.*; -import javax.validation.constraints.NotNull; -import java.util.List; - -/* -This is a placeholder Entity for an "Authority" POJO. Feel free to modify/edit as needed -for compatibility with actual database Table -*/ - -@Entity -@Table(name = "ie_AUTHORITY") -public class Authority { - - @Id - @Column(name = "a_authID") - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "authority_seq") - @SequenceGenerator(name = "authority_seq", sequenceName = "authority_seq", allocationSize = 1) - private Long id; - - @Column(name = "a_authorityName", length = 50) - @NotNull - @Enumerated(EnumType.STRING) - private AuthorityName name; - - @ManyToMany(mappedBy = "authorities", fetch = FetchType.LAZY) - private List users; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public AuthorityName getName() { - return name; - } - - public void setName(AuthorityName name) { - this.name = name; - } - - public List getUsers() { - return users; - } - - public void setUsers(List users) { - this.users = users; - } -} \ No newline at end of file diff --git a/src/main/java/com/revature/security/extra/model/AuthorityName.java b/src/main/java/com/revature/security/extra/model/AuthorityName.java deleted file mode 100644 index 4b44a5a..0000000 --- a/src/main/java/com/revature/security/extra/model/AuthorityName.java +++ /dev/null @@ -1,14 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package com.revature.security.extra; - -/** - * - * @author FayeRedd - */ -public enum AuthorityName { - ROLE_USER, ROLE_ADMIN -} diff --git a/src/main/java/com/revature/security/extra/model/User.java b/src/main/java/com/revature/security/extra/model/User.java deleted file mode 100644 index 09efec2..0000000 --- a/src/main/java/com/revature/security/extra/model/User.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package com.revature.security.extra; - -/** - * - * @author FayeRedd - */ -import java.util.Date; -import java.util.List; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.JoinTable; -import javax.persistence.ManyToMany; -import javax.persistence.SequenceGenerator; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - -/* -This is a placeholder Entity for the User POJO. Feel free to modify/edit as needed -for compatibility with actual database Table -*/ - -@Entity -@Table(name = "ie_user") -public class User { - - @Id - @Column(name = "u_userID") - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_seq") - @SequenceGenerator(name = "user_seq", sequenceName = "user_seq", allocationSize = 1) - private Long id; - - @Column(name = "u_username", length = 50, unique = true) - @NotNull - @Size(min = 4, max = 50) - private String username; - - @Column(name = "u_password", length = 100) - @NotNull - @Size(min = 4, max = 100) - private String password; - - @Column(name = "u_firstName", length = 50) - @NotNull - @Size(min = 4, max = 50) - private String firstname; - - @Column(name = "u_lastName", length = 50) - @NotNull - @Size(min = 4, max = 50) - private String lastname; - - @Column(name = "u_email", length = 50) - @NotNull - @Size(min = 4, max = 50) - private String email; - - @Column(name = "u_enabled") - @NotNull - private Boolean enabled; - - @Column(name = "u_lastpasswordresetdate") - @Temporal(TemporalType.TIMESTAMP) - @NotNull - private Date lastPasswordResetDate; - - @ManyToMany(fetch = FetchType.EAGER) - @JoinTable( - name = "ua_user_authority", - joinColumns = {@JoinColumn(name = "u_user_id", referencedColumnName = "u_userID")}, - inverseJoinColumns = {@JoinColumn(name = "a_authority_id", referencedColumnName = "a_authID")}) - private List authorities; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - 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 getFirstname() { - return firstname; - } - - public void setFirstname(String firstname) { - this.firstname = firstname; - } - - public String getLastname() { - return lastname; - } - - public void setLastname(String lastname) { - this.lastname = lastname; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public Boolean getEnabled() { - return enabled; - } - - public void setEnabled(Boolean enabled) { - this.enabled = enabled; - } - - public List getAuthorities() { - return authorities; - } - - public void setAuthorities(List authorities) { - this.authorities = authorities; - } - - public Date getLastPasswordResetDate() { - return lastPasswordResetDate; - } - - public void setLastPasswordResetDate(Date lastPasswordResetDate) { - this.lastPasswordResetDate = lastPasswordResetDate; - } -} diff --git a/src/main/java/com/revature/security/extra/service/JwtAuthenticationResponse.java b/src/main/java/com/revature/security/extra/service/JwtAuthenticationResponse.java deleted file mode 100644 index 6c65e7c..0000000 --- a/src/main/java/com/revature/security/extra/service/JwtAuthenticationResponse.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package com.revature.security.extra; - -import java.io.Serializable; - -/** - * - * @author FayeRedd - */ -public class JwtAuthenticationResponse implements Serializable { - - private static final long serialVersionUID = 1250166508152483573L; - - private final String token; - - public JwtAuthenticationResponse(String token) { - this.token = token; - } - - public String getToken() { - return this.token; - } -} diff --git a/src/main/java/com/revature/security/extra/service/JwtUserDetailsServiceImpl.java b/src/main/java/com/revature/security/extra/service/JwtUserDetailsServiceImpl.java deleted file mode 100644 index 88179f7..0000000 --- a/src/main/java/com/revature/security/extra/service/JwtUserDetailsServiceImpl.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package com.revature.security.extra; - -import com.revature.security.extra.User; -import com.revature.security.extra.JwtUserFactory; -import com.revature.repositories.UserRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.stereotype.Service; - -/** - * - * @author FayeRedd - */ -@Service -public class JwtUserDetailsServiceImpl implements UserDetailsService { - - @Autowired - private UserRepository userRepository; - - @Override - public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { - User user = userRepository.findByUsername(username); - - if (user == null) { - throw new UsernameNotFoundException(String.format("No user found with username '%s'.", username)); - } else { - return JwtUserFactory.create(user); - } - } - -// @Override -// public UserDetails loadUserByUsername(String string) throws UsernameNotFoundException { -// throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. -// } -} \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml deleted file mode 100644 index b7c36fe..0000000 --- a/src/main/resources/application.yml +++ /dev/null @@ -1,21 +0,0 @@ -## YAML Template. ---- -server: - contextPath: - - -# JACKSON - -spring: - jackson: - serialization: - INDENT_OUTPUT: true - -jwt: - header: Authorization - secret: mySecret - expiration: 604800 - route: - authentication: - path: auth - refresh: refresh \ No newline at end of file diff --git a/src/test/java/com/revature/InterviewEvaluationsApplicationTests.java b/src/test/java/com/revature/InterviewEvaluationsApplicationTests.java deleted file mode 100644 index e2e449e..0000000 --- a/src/test/java/com/revature/InterviewEvaluationsApplicationTests.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.revature; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest -public class InterviewEvaluationsApplicationTests { - - @Test - public void contextLoads() { - } - -} diff --git a/src/test/java/com/revature/security/extra/JwtTokenTest.java b/src/test/java/com/revature/security/extra/JwtTokenTest.java deleted file mode 100644 index c11ee71..0000000 --- a/src/test/java/com/revature/security/extra/JwtTokenTest.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * The MIT License - * - */ -package com.revature.security.extra; - -import com.revature.security.extra.JwtTokenUtil; -import java.util.HashMap; -import java.util.Map; -import org.assertj.core.util.DateUtil; -import static org.assertj.core.api.Assertions.assertThat; -import org.junit.Before; -import org.junit.Test; -import org.springframework.test.util.ReflectionTestUtils; - -/** - * - * @author FayeRedd - */ -public class JwtTokenTest { - private JwtTokenUtil jwtTokenUtil; - - @Before - public void init() { - jwtTokenUtil = new JwtTokenUtil(); - ReflectionTestUtils.setField(jwtTokenUtil, "expiration", 3600000L); - ReflectionTestUtils.setField(jwtTokenUtil, "secret", "mySecret"); - } - - @Test - public void testGenerateTokenGeneratesDifferentTokensForDifferentCreationDates() throws Exception { - final Map claims = createClaims("2016-09-08T03:00:00"); - final String token = jwtTokenUtil.generateToken(claims); - - final Map claimsForLaterToken = createClaims("2016-09-08T08:00:00"); - final String laterToken = jwtTokenUtil.generateToken(claimsForLaterToken); - - assertThat(token).isNotEqualTo(laterToken); - } - - private Map createClaims(String creationDate) { - Map claims = new HashMap(); - claims.put(JwtTokenUtil.CLAIM_KEY_USERNAME, "testUser"); - claims.put(JwtTokenUtil.CLAIM_KEY_AUDIENCE, "testAudience"); - claims.put(JwtTokenUtil.CLAIM_KEY_CREATED, DateUtil.parseDatetime(creationDate)); - return claims; - } - -} diff --git a/src/test/java/com/revature/spring/test/PersonEntityTest.java b/src/test/java/com/revature/spring/test/PersonEntityTest.java deleted file mode 100644 index e69de29..0000000 From dca058769a5c83f82350c849cb58c3a7902caa3a Mon Sep 17 00:00:00 2001 From: Madison Date: Wed, 12 Apr 2017 15:57:40 -0700 Subject: [PATCH 17/19] fix dependency compatibility --- pom.xml | 18 +++--- .../InterviewEvaluationsApplication.java | 9 +-- .../revature/config/WebSecurityConfig.java | 2 +- .../JwtAuthenticationEntryPoint.java | 2 +- .../security/JwtAuthenticationFilter.java | 59 +++++++++++++++++++ .../exceptions/JwtTokenMissingException.java | 2 +- 6 files changed, 74 insertions(+), 18 deletions(-) rename src/main/java/com/revature/security/{core => }/JwtAuthenticationEntryPoint.java (96%) create mode 100644 src/main/java/com/revature/security/JwtAuthenticationFilter.java rename src/main/java/com/revature/security/{core => }/exceptions/JwtTokenMissingException.java (89%) diff --git a/pom.xml b/pom.xml index edb890b..9870540 100644 --- a/pom.xml +++ b/pom.xml @@ -4,8 +4,8 @@ 4.0.0 com.revature - interview-evaluations - 0.0.1-SNAPSHOT + interview-evaluations + 0.0.1-SNAPSHOT jar interview-evaluations @@ -140,13 +140,13 @@ jar - - - com.revature - RevatureSecurityLogin - 1.0-SNAPSHOT - compile - + + com.revsecurity + RevatureSecurity + 1.0-SNAPSHOT + compile + + diff --git a/src/main/java/com/revature/InterviewEvaluationsApplication.java b/src/main/java/com/revature/InterviewEvaluationsApplication.java index 5b74add..08801d1 100644 --- a/src/main/java/com/revature/InterviewEvaluationsApplication.java +++ b/src/main/java/com/revature/InterviewEvaluationsApplication.java @@ -10,10 +10,7 @@ @SpringBootApplication public class InterviewEvaluationsApplication { - public static void main(String[] args) { - - SpringApplication.run(InterviewEvaluationsApplication.class, args); - - } - + public static void main(String[] args) { + SpringApplication.run(InterviewEvaluationsApplication.class, args); + } } diff --git a/src/main/java/com/revature/config/WebSecurityConfig.java b/src/main/java/com/revature/config/WebSecurityConfig.java index 07cd32b..9cb84ed 100644 --- a/src/main/java/com/revature/config/WebSecurityConfig.java +++ b/src/main/java/com/revature/config/WebSecurityConfig.java @@ -5,7 +5,7 @@ */ package com.revature.config; -import com.revature.security.core.JwtAuthenticationEntryPoint; +import com.revature.security.JwtAuthenticationEntryPoint; import com.revature.security.JwtAuthenticationFilter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; diff --git a/src/main/java/com/revature/security/core/JwtAuthenticationEntryPoint.java b/src/main/java/com/revature/security/JwtAuthenticationEntryPoint.java similarity index 96% rename from src/main/java/com/revature/security/core/JwtAuthenticationEntryPoint.java rename to src/main/java/com/revature/security/JwtAuthenticationEntryPoint.java index 5302f7c..f9a171b 100644 --- a/src/main/java/com/revature/security/core/JwtAuthenticationEntryPoint.java +++ b/src/main/java/com/revature/security/JwtAuthenticationEntryPoint.java @@ -3,7 +3,7 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package com.revature.security.core; +package com.revature.security; import java.io.IOException; import java.io.Serializable; diff --git a/src/main/java/com/revature/security/JwtAuthenticationFilter.java b/src/main/java/com/revature/security/JwtAuthenticationFilter.java new file mode 100644 index 0000000..07a3f2a --- /dev/null +++ b/src/main/java/com/revature/security/JwtAuthenticationFilter.java @@ -0,0 +1,59 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security; + +import com.revature.revatureSecurity.JwtTokenUtil; +import java.io.IOException; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.web.filter.OncePerRequestFilter; + +/** + * + * @author FayeRedd + */ +public class JwtAuthenticationFilter extends OncePerRequestFilter { + + @Autowired + private UserDetailsService userDetailsService; + + @Autowired + private JwtTokenUtil jwtTokenUtil; + + @Value("${jwt.header}") + private String tokenHeader; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { + String authToken = request.getHeader(this.tokenHeader); + + String username = jwtTokenUtil.getUsernameFromToken(authToken); + + if(username != null && SecurityContextHolder.getContext().getAuthentication() == null){ + UserDetails userDetails = this.userDetailsService.loadUserByUsername(username); + + if(jwtTokenUtil.validateToken(authToken, userDetails)){ + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); + + authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + + SecurityContextHolder.getContext().setAuthentication(authentication); + } + } + chain.doFilter(request, response); + } +} diff --git a/src/main/java/com/revature/security/core/exceptions/JwtTokenMissingException.java b/src/main/java/com/revature/security/exceptions/JwtTokenMissingException.java similarity index 89% rename from src/main/java/com/revature/security/core/exceptions/JwtTokenMissingException.java rename to src/main/java/com/revature/security/exceptions/JwtTokenMissingException.java index 062fb25..6c2a485 100644 --- a/src/main/java/com/revature/security/core/exceptions/JwtTokenMissingException.java +++ b/src/main/java/com/revature/security/exceptions/JwtTokenMissingException.java @@ -3,7 +3,7 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package com.revature.security.core.exceptions; +package com.revature.security.exceptions; /** * From 9ef22cb2892afc826dfde98cd520aadc73c92e00 Mon Sep 17 00:00:00 2001 From: Madison Date: Fri, 14 Apr 2017 16:02:19 -0700 Subject: [PATCH 18/19] Fully Functional. All files included under any package named 'extra' are to be removed and placed in a seperate Authorization Server service. All files in the 'static' folder likewise belong to the future Authorization Server service --- pom.xml | 4 +- .../revature/config/WebSecurityConfig.java | 2 +- .../revature/controllers/BatchController.java | 2 + .../repositories/extra/UserRepository.java | 22 +++ .../security/JwtAuthenticationRequest.java | 45 +++++ .../{ => extra}/JwtAuthenticationFilter.java | 4 +- .../extra/JwtAuthenticationResponse.java | 27 +++ .../revature/security/extra/JwtTokenUtil.java | 186 ++++++++++++++++++ .../com/revature/security/extra/JwtUser.java | 113 +++++++++++ .../security/extra/JwtUserFactory.java | 45 +++++ .../AuthenticationRestController.java | 83 ++++++++ .../extra/controllers/UserRestController.java | 48 +++++ .../security/extra/model/Authority.java | 62 ++++++ .../security/extra/model/AuthorityName.java | 14 ++ .../revature/security/extra/model/User.java | 158 +++++++++++++++ .../service/JwtUserDetailsServiceImpl.java | 37 ++++ src/main/resources/application.yml | 23 +++ src/main/resources/static/index.html | 117 +++++++++++ src/main/resources/static/js/client.js | 175 ++++++++++++++++ 19 files changed, 1162 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/revature/repositories/extra/UserRepository.java create mode 100644 src/main/java/com/revature/security/JwtAuthenticationRequest.java rename src/main/java/com/revature/security/{ => extra}/JwtAuthenticationFilter.java (96%) create mode 100644 src/main/java/com/revature/security/extra/JwtAuthenticationResponse.java create mode 100644 src/main/java/com/revature/security/extra/JwtTokenUtil.java create mode 100644 src/main/java/com/revature/security/extra/JwtUser.java create mode 100644 src/main/java/com/revature/security/extra/JwtUserFactory.java create mode 100644 src/main/java/com/revature/security/extra/controllers/AuthenticationRestController.java create mode 100644 src/main/java/com/revature/security/extra/controllers/UserRestController.java create mode 100644 src/main/java/com/revature/security/extra/model/Authority.java create mode 100644 src/main/java/com/revature/security/extra/model/AuthorityName.java create mode 100644 src/main/java/com/revature/security/extra/model/User.java create mode 100644 src/main/java/com/revature/security/extra/service/JwtUserDetailsServiceImpl.java create mode 100644 src/main/resources/application.yml create mode 100644 src/main/resources/static/index.html create mode 100644 src/main/resources/static/js/client.js diff --git a/pom.xml b/pom.xml index 9870540..e715c42 100644 --- a/pom.xml +++ b/pom.xml @@ -139,14 +139,14 @@ 4.2.1.RELEASE jar - + diff --git a/src/main/java/com/revature/config/WebSecurityConfig.java b/src/main/java/com/revature/config/WebSecurityConfig.java index 9cb84ed..46824c3 100644 --- a/src/main/java/com/revature/config/WebSecurityConfig.java +++ b/src/main/java/com/revature/config/WebSecurityConfig.java @@ -6,7 +6,7 @@ package com.revature.config; import com.revature.security.JwtAuthenticationEntryPoint; -import com.revature.security.JwtAuthenticationFilter; +import com.revature.security.extra.JwtAuthenticationFilter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/src/main/java/com/revature/controllers/BatchController.java b/src/main/java/com/revature/controllers/BatchController.java index dc26831..692d52c 100644 --- a/src/main/java/com/revature/controllers/BatchController.java +++ b/src/main/java/com/revature/controllers/BatchController.java @@ -6,6 +6,7 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; @@ -16,6 +17,7 @@ @CrossOrigin @RestController @RequestMapping(value = "/api/v1/") +@PreAuthorize("hasRole('ADMIN')") public class BatchController { @Autowired diff --git a/src/main/java/com/revature/repositories/extra/UserRepository.java b/src/main/java/com/revature/repositories/extra/UserRepository.java new file mode 100644 index 0000000..886c40c --- /dev/null +++ b/src/main/java/com/revature/repositories/extra/UserRepository.java @@ -0,0 +1,22 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.repositories.extra; + +import com.revature.security.extra.model.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +/** + * + * @author FayeRedd + */ + +@Repository +public interface UserRepository extends JpaRepository { + + User findByUsername(String username); + +} diff --git a/src/main/java/com/revature/security/JwtAuthenticationRequest.java b/src/main/java/com/revature/security/JwtAuthenticationRequest.java new file mode 100644 index 0000000..c6555c9 --- /dev/null +++ b/src/main/java/com/revature/security/JwtAuthenticationRequest.java @@ -0,0 +1,45 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security; + +import java.io.Serializable; + +/** + * + * @author FayeRedd + */ +public class JwtAuthenticationRequest implements Serializable { + + private static final long serialVersionUID = -8445943548965154778L; + + private String username; + private String password; + + public JwtAuthenticationRequest() { + super(); + } + + public JwtAuthenticationRequest(String username, String password) { + this.setUsername(username); + this.setPassword(password); + } + + public String getUsername() { + return this.username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return this.password; + } + + public void setPassword(String password) { + this.password = password; + } +} diff --git a/src/main/java/com/revature/security/JwtAuthenticationFilter.java b/src/main/java/com/revature/security/extra/JwtAuthenticationFilter.java similarity index 96% rename from src/main/java/com/revature/security/JwtAuthenticationFilter.java rename to src/main/java/com/revature/security/extra/JwtAuthenticationFilter.java index 07a3f2a..22add8c 100644 --- a/src/main/java/com/revature/security/JwtAuthenticationFilter.java +++ b/src/main/java/com/revature/security/extra/JwtAuthenticationFilter.java @@ -3,9 +3,9 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package com.revature.security; +package com.revature.security.extra; -import com.revature.revatureSecurity.JwtTokenUtil; +import com.revature.security.extra.JwtTokenUtil; import java.io.IOException; import javax.servlet.FilterChain; diff --git a/src/main/java/com/revature/security/extra/JwtAuthenticationResponse.java b/src/main/java/com/revature/security/extra/JwtAuthenticationResponse.java new file mode 100644 index 0000000..265a882 --- /dev/null +++ b/src/main/java/com/revature/security/extra/JwtAuthenticationResponse.java @@ -0,0 +1,27 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.revatureSecurity; + +import java.io.Serializable; + +/** + * + * @author FayeRedd + */ +public class JwtAuthenticationResponse implements Serializable { + + private static final long serialVersionUID = 1250166508152483573L; + + private final String token; + + public JwtAuthenticationResponse(String token) { + this.token = token; + } + + public String getToken() { + return this.token; + } +} diff --git a/src/main/java/com/revature/security/extra/JwtTokenUtil.java b/src/main/java/com/revature/security/extra/JwtTokenUtil.java new file mode 100644 index 0000000..338459a --- /dev/null +++ b/src/main/java/com/revature/security/extra/JwtTokenUtil.java @@ -0,0 +1,186 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security.extra; + +/** + * + * @author FayeRedd + */ + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.ExpiredJwtException; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.MalformedJwtException; +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.SignatureException; +import io.jsonwebtoken.UnsupportedJwtException; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.mobile.device.Device; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Component; + +import java.io.Serializable; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/* +* This class is the demo token generator/validator. It can be replaced in the future with +* a microservice providing these same features +*/ + +@Component +public class JwtTokenUtil implements Serializable { + + private static final long serialVersionUID = -3301605591108950415L; + + static final String CLAIM_KEY_USERNAME = "sub"; + static final String CLAIM_KEY_AUDIENCE = "audience"; + static final String CLAIM_KEY_CREATED = "created"; + + private static final String AUDIENCE_UNKNOWN = "unknown"; + private static final String AUDIENCE_WEB = "web"; + private static final String AUDIENCE_MOBILE = "mobile"; + private static final String AUDIENCE_TABLET = "tablet"; + + //This value is stored in the application.yml file + @Value("${jwt.secret}") + private String secret; + + //This value is stored in the application.yml file + @Value("${jwt.expiration}") + private Long expiration; + + public String getUsernameFromToken(String token) { + String username; + try { + final Claims claims = getClaimsFromToken(token); + username = claims.getSubject(); + } catch (Exception e) { + username = null; + } + return username; + } + + public Date getCreatedDateFromToken(String token) { + Date created; + try { + final Claims claims = getClaimsFromToken(token); + created = new Date((Long) claims.get(CLAIM_KEY_CREATED)); + } catch (Exception e) { + created = null; + } + return created; + } + + public Date getExpirationDateFromToken(String token) { + Date expires; + try { + final Claims claims = getClaimsFromToken(token); + expires = claims.getExpiration(); + } catch (Exception e) { + expires = null; + } + return expires; + } + + public String getAudienceFromToken(String token) { + String audience; + try { + final Claims claims = getClaimsFromToken(token); + audience = (String) claims.get(CLAIM_KEY_AUDIENCE); + } catch (Exception e) { + audience = null; + } + return audience; + } + + private Claims getClaimsFromToken(String token) { + Claims claims; + try { + claims = Jwts.parser() + .setSigningKey(secret) + .parseClaimsJws(token) + .getBody(); + } catch (ExpiredJwtException | MalformedJwtException | SignatureException | UnsupportedJwtException | IllegalArgumentException e) { + claims = null; + } + return claims; + } + + private Date generateExpirationDate() { + return new Date(System.currentTimeMillis() + expiration * 1000); + } + + private Boolean isTokenExpired(String token) { + final Date expires = getExpirationDateFromToken(token); + return expires.before(new Date()); + } + + private Boolean isCreatedBeforeLastPasswordReset(Date created, Date lastPasswordReset) { + return lastPasswordReset != null && created.before(lastPasswordReset); + } + + private String generateAudience(Device device) { + String audience = AUDIENCE_UNKNOWN; + if (device.isNormal()) { + audience = AUDIENCE_WEB; + } else if (device.isTablet()) { + audience = AUDIENCE_TABLET; + } else if (device.isMobile()) { + audience = AUDIENCE_MOBILE; + } + return audience; + } + + private Boolean ignoreTokenExpiration(String token) { + String audience = getAudienceFromToken(token); + return AUDIENCE_TABLET.equals(audience) || AUDIENCE_MOBILE.equals(audience); + } + + public String generateToken(UserDetails userDetails, Device device) { + Map claims = new HashMap<>(); + claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername()); + claims.put(CLAIM_KEY_AUDIENCE, generateAudience(device)); + claims.put(CLAIM_KEY_CREATED, new Date()); + return generateToken(claims); + } + + String generateToken(Map claims) { + return Jwts.builder() + .setClaims(claims) + .setExpiration(generateExpirationDate()) + .signWith(SignatureAlgorithm.HS512, secret) + .compact(); + } + + public Boolean canTokenBeRefreshed(String token, Date lastPasswordReset) { + final Date created = getCreatedDateFromToken(token); + return !isCreatedBeforeLastPasswordReset(created, lastPasswordReset) + && (!isTokenExpired(token) || ignoreTokenExpiration(token)); + } + + public String refreshToken(String token) { + String refreshedToken; + try { + final Claims claims = getClaimsFromToken(token); + claims.put(CLAIM_KEY_CREATED, new Date()); + refreshedToken = generateToken(claims); + } catch (Exception e) { + refreshedToken = null; + } + return refreshedToken; + } + + public Boolean validateToken(String token, UserDetails userDetails) { + JwtUser user = (JwtUser) userDetails; + final String username = getUsernameFromToken(token); + final Date created = getCreatedDateFromToken(token); + return username.equals(user.getUsername()) + && !isTokenExpired(token) + && !isCreatedBeforeLastPasswordReset(created, user.getLastPasswordResetDate()); + } +} \ No newline at end of file diff --git a/src/main/java/com/revature/security/extra/JwtUser.java b/src/main/java/com/revature/security/extra/JwtUser.java new file mode 100644 index 0000000..36c5e62 --- /dev/null +++ b/src/main/java/com/revature/security/extra/JwtUser.java @@ -0,0 +1,113 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security.extra; + +/** + * + * @author FayeRedd + */ +import java.util.Collection; +import java.util.Date; + +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +public class JwtUser implements UserDetails { + + private final Long id; + private final String username; + private final String firstname; + private final String lastname; + private final String password; + private final String email; + private final Collection authorities; + private final boolean enabled; + private final Date lastPasswordResetDate; + + public JwtUser( + Long id, + String username, + String firstname, + String lastname, + String email, + String password, Collection authorities, + boolean enabled, + Date lastPasswordResetDate + ) { + this.id = id; + this.username = username; + this.firstname = firstname; + this.lastname = lastname; + this.email = email; + this.password = password; + this.authorities = authorities; + this.enabled = enabled; + this.lastPasswordResetDate = lastPasswordResetDate; + } + + @JsonIgnore + public Long getId() { + return id; + } + + @Override + public String getUsername() { + return username; + } + + @JsonIgnore + @Override + public boolean isAccountNonExpired() { + return true; + } + + @JsonIgnore + @Override + public boolean isAccountNonLocked() { + return true; + } + + @JsonIgnore + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + public String getFirstname() { + return firstname; + } + + public String getLastname() { + return lastname; + } + + public String getEmail() { + return email; + } + + @JsonIgnore + @Override + public String getPassword() { + return password; + } + + @Override + public Collection getAuthorities() { + return authorities; + } + + @Override + public boolean isEnabled() { + return enabled; + } + + @JsonIgnore + public Date getLastPasswordResetDate() { + return lastPasswordResetDate; + } +} diff --git a/src/main/java/com/revature/security/extra/JwtUserFactory.java b/src/main/java/com/revature/security/extra/JwtUserFactory.java new file mode 100644 index 0000000..805def8 --- /dev/null +++ b/src/main/java/com/revature/security/extra/JwtUserFactory.java @@ -0,0 +1,45 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security.extra; + +import com.revature.security.extra.model.Authority; +import com.revature.security.extra.model.User; +import java.util.List; +import java.util.stream.Collectors; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; + + + +/** + * + * @author FayeRedd + */ +public class JwtUserFactory { + + private JwtUserFactory(){} + + public static JwtUser create(User user){ + return new JwtUser( + user.getId(), + user.getUsername(), + user.getFirstname(), + user.getLastname(), + user.getEmail(), + user.getPassword(), + mapToGrantedAuthorities(user.getAuthorities()), + user.getEnabled(), + user.getLastPasswordResetDate() + ); + } + + private static List mapToGrantedAuthorities(List authorities) { + return authorities.stream() + .map(authority -> new SimpleGrantedAuthority(authority.getName().name())) + .collect(Collectors.toList()); + } + +} diff --git a/src/main/java/com/revature/security/extra/controllers/AuthenticationRestController.java b/src/main/java/com/revature/security/extra/controllers/AuthenticationRestController.java new file mode 100644 index 0000000..2464ad2 --- /dev/null +++ b/src/main/java/com/revature/security/extra/controllers/AuthenticationRestController.java @@ -0,0 +1,83 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security.extra.controllers; + +import com.revature.security.JwtAuthenticationRequest; +import com.revature.security.extra.JwtTokenUtil; +import com.revature.security.extra.JwtUser; +import com.revature.revatureSecurity.JwtAuthenticationResponse; +import javax.servlet.http.HttpServletRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.ResponseEntity; +import org.springframework.mobile.device.Device; +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.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.security.core.userdetails.UserDetails; + +/** + * + * @author FayeRedd + */ + +@RestController +public class AuthenticationRestController { + + //This value can be found in the application.yml file + @Value("${jwt.header}") + private String tokenHeader; + + @Autowired + private AuthenticationManager authMan; + + //This is the token generator/validator. Can be replaced with future microservice providing/varifying tokens + @Autowired + private JwtTokenUtil tokenUtil; + + @Autowired + private UserDetailsService userDetServ; + + //This value can be found in the application.yml file + @RequestMapping(value = "${jwt.route.authentication.path}", method = RequestMethod.POST) + public ResponseEntity createAuthenticationToken(@RequestBody JwtAuthenticationRequest authReq, Device dev) throws AuthenticationException{ + + final Authentication authentication = authMan.authenticate( + new UsernamePasswordAuthenticationToken( + authReq.getUsername(), + authReq.getPassword()) + ); + + SecurityContextHolder.getContext().setAuthentication(authentication); + + final UserDetails userDetails = userDetServ.loadUserByUsername(authReq.getUsername()); + final String token = tokenUtil.generateToken(userDetails, dev); + + return ResponseEntity.ok(new JwtAuthenticationResponse(token)); + } + + //This value can be found in the application.yml file + @RequestMapping(value = "${jwt.route.authentication.refresh}", method = RequestMethod.GET) + public ResponseEntity refreshAndGetAuthenticationToken(HttpServletRequest req){ + String token = req.getHeader(tokenHeader); + String username = tokenUtil.getUsernameFromToken(token); + JwtUser user = (JwtUser) userDetServ.loadUserByUsername(username); + + if(tokenUtil.canTokenBeRefreshed(token, user.getLastPasswordResetDate())){ + String refreshedToken = tokenUtil.refreshToken(token); + return ResponseEntity.ok(new JwtAuthenticationResponse(refreshedToken)); + } else { + return ResponseEntity.badRequest().body(null); + } + } +} diff --git a/src/main/java/com/revature/security/extra/controllers/UserRestController.java b/src/main/java/com/revature/security/extra/controllers/UserRestController.java new file mode 100644 index 0000000..f1a4a95 --- /dev/null +++ b/src/main/java/com/revature/security/extra/controllers/UserRestController.java @@ -0,0 +1,48 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security.extra.controllers; + +import com.revature.security.extra.JwtTokenUtil; +import com.revature.security.extra.JwtUser; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +/** + * + * @author FayeRedd + */ + +@RestController +public class UserRestController { + + //This value is found in the application.yml file + @Value("${jwt.header}") + private String tokenHeader; + + //This is the token generator/validator. Can be replaced with future microservice providing/varifying tokens + @Autowired + private JwtTokenUtil jwtTokenUtil; + + @Autowired + private UserDetailsService userDetailsService; + + @RequestMapping(value="user", method = RequestMethod.GET) + public JwtUser getAuthenticatedUser(HttpServletRequest req){ + + String token = req.getHeader(tokenHeader); + String username = jwtTokenUtil.getUsernameFromToken(token); + JwtUser user = (JwtUser) userDetailsService.loadUserByUsername(username); + + return user; + } +} \ No newline at end of file diff --git a/src/main/java/com/revature/security/extra/model/Authority.java b/src/main/java/com/revature/security/extra/model/Authority.java new file mode 100644 index 0000000..b3166fb --- /dev/null +++ b/src/main/java/com/revature/security/extra/model/Authority.java @@ -0,0 +1,62 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security.extra.model; + +/** + * + * @author FayeRedd + */ +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import java.util.List; + +/* +This is a placeholder Entity for an "Authority" POJO. Feel free to modify/edit as needed +for compatibility with actual database Table +*/ + +@Entity +@Table(name = "ie_authority") +public class Authority { + + @Id + @Column(name = "a_authid") + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "authority_seq") + @SequenceGenerator(name = "authority_seq", sequenceName = "authority_seq", allocationSize = 1) + private Long id; + + @Column(name = "a_authorityname", length = 50) + @NotNull + @Enumerated(EnumType.STRING) + private AuthorityName name; + + @ManyToMany(mappedBy = "authorities", fetch = FetchType.LAZY) + private List users; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public AuthorityName getName() { + return name; + } + + public void setName(AuthorityName name) { + this.name = name; + } + + public List getUsers() { + return users; + } + + public void setUsers(List users) { + this.users = users; + } +} \ No newline at end of file diff --git a/src/main/java/com/revature/security/extra/model/AuthorityName.java b/src/main/java/com/revature/security/extra/model/AuthorityName.java new file mode 100644 index 0000000..c802732 --- /dev/null +++ b/src/main/java/com/revature/security/extra/model/AuthorityName.java @@ -0,0 +1,14 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security.extra.model; + +/** + * + * @author FayeRedd + */ +public enum AuthorityName { + ROLE_USER, ROLE_ADMIN +} diff --git a/src/main/java/com/revature/security/extra/model/User.java b/src/main/java/com/revature/security/extra/model/User.java new file mode 100644 index 0000000..53af8eb --- /dev/null +++ b/src/main/java/com/revature/security/extra/model/User.java @@ -0,0 +1,158 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security.extra.model; + +/** + * + * @author FayeRedd + */ +import java.util.Date; +import java.util.List; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToMany; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +/* +This is a placeholder Entity for the User POJO. Feel free to modify/edit as needed +for compatibility with actual database Table +*/ + +@Entity +@Table(name = "ie_user") +public class User { + + @Id + @Column(name = "u_userid") + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_seq") + @SequenceGenerator(name = "user_seq", sequenceName = "user_seq", allocationSize = 1) + private Long id; + + @Column(name = "u_username", length = 50, unique = true) + @NotNull + @Size(min = 4, max = 50) + private String username; + + @Column(name = "u_password", length = 100) + @NotNull + @Size(min = 4, max = 100) + private String password; + + @Column(name = "u_firstname", length = 50) + @NotNull + @Size(min = 4, max = 50) + private String firstname; + + @Column(name = "u_lastname", length = 50) + @NotNull + @Size(min = 4, max = 50) + private String lastname; + + @Column(name = "u_email", length = 50) + @NotNull + @Size(min = 4, max = 50) + private String email; + + @Column(name = "u_enabled") + @NotNull + private Boolean enabled; + + @Column(name = "u_lastpasswordresetdate") + @Temporal(TemporalType.TIMESTAMP) + @NotNull + private Date lastPasswordResetDate; + + @ManyToMany(fetch = FetchType.EAGER) + @JoinTable( + name = "ie_user_authority", + joinColumns = {@JoinColumn(name = "ua_user_id", referencedColumnName = "u_userid")}, + inverseJoinColumns = {@JoinColumn(name = "ua_authority_id", referencedColumnName = "a_authid")}) + private List authorities; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + 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 getFirstname() { + return firstname; + } + + public void setFirstname(String firstname) { + this.firstname = firstname; + } + + public String getLastname() { + return lastname; + } + + public void setLastname(String lastname) { + this.lastname = lastname; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public Boolean getEnabled() { + return enabled; + } + + public void setEnabled(Boolean enabled) { + this.enabled = enabled; + } + + public List getAuthorities() { + return authorities; + } + + public void setAuthorities(List authorities) { + this.authorities = authorities; + } + + public Date getLastPasswordResetDate() { + return lastPasswordResetDate; + } + + public void setLastPasswordResetDate(Date lastPasswordResetDate) { + this.lastPasswordResetDate = lastPasswordResetDate; + } +} diff --git a/src/main/java/com/revature/security/extra/service/JwtUserDetailsServiceImpl.java b/src/main/java/com/revature/security/extra/service/JwtUserDetailsServiceImpl.java new file mode 100644 index 0000000..647f785 --- /dev/null +++ b/src/main/java/com/revature/security/extra/service/JwtUserDetailsServiceImpl.java @@ -0,0 +1,37 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.revature.security.extra.service; + +import com.revature.security.extra.JwtUserFactory; +import com.revature.security.extra.model.User; +import com.revature.repositories.extra.UserRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +/** + * + * @author FayeRedd + */ +@Service +public class JwtUserDetailsServiceImpl implements UserDetailsService { + + @Autowired + private UserRepository userRepository; + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + User user = userRepository.findByUsername(username); + + if (user == null) { + throw new UsernameNotFoundException(String.format("No user found with username '%s'.", username)); + } else { + return JwtUserFactory.create(user); + } + } +} \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..9b24ad4 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,23 @@ +# config context path to "/" by setting an empty string +server: + contextPath: + +# JACKSON +spring: + jackson: + serialization: + INDENT_OUTPUT: true + +jwt: + header: Authorization + secret: mySecret + expiration: 604800 + route: + authentication: + path: auth + refresh: refresh + +#logging: +# level: +# org.springframework: +# security: DEBUG \ No newline at end of file diff --git a/src/main/resources/static/index.html b/src/main/resources/static/index.html new file mode 100644 index 0000000..60e270d --- /dev/null +++ b/src/main/resources/static/index.html @@ -0,0 +1,117 @@ + + + + + JWT Spring Security Demo + + + + + + + + + + +
+

JWT Spring Security Demo

+ +
Not logged in!
+ +
+ +
+
+
+
+

Login

+
+
+
+
+ +
+
+ +
+
+ Try one of the following logins +
    +
  • admin & admin
  • +
  • user & password
  • +
  • disabled & password
  • +
+
+ +
+
+
+ +
+
+
+

Authenticated user

+
+
+
+ +
+
+
+
+ +
+
+ + +
+
+
+

Response:

+
+
+

+                
+
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/static/js/client.js b/src/main/resources/static/js/client.js new file mode 100644 index 0000000..2c0fb4d --- /dev/null +++ b/src/main/resources/static/js/client.js @@ -0,0 +1,175 @@ +/** + * Created by stephan on 20.03.16. + */ + +$(function () { + // VARIABLES ============================================================= + var TOKEN_KEY = "jwtToken" + var $notLoggedIn = $("#notLoggedIn"); + var $loggedIn = $("#loggedIn").hide(); + var $response = $("#response"); + var $login = $("#login"); + var $userInfo = $("#userInfo").hide(); + + // FUNCTIONS ============================================================= + function getJwtToken() { + return localStorage.getItem(TOKEN_KEY); + } + + function setJwtToken(token) { + localStorage.setItem(TOKEN_KEY, token); + } + + function removeJwtToken() { + localStorage.removeItem(TOKEN_KEY); + } + + function doLogin(loginData) { + $.ajax({ + url: "/auth", + type: "POST", + data: JSON.stringify(loginData), + contentType: "application/json; charset=utf-8", + dataType: "json", + success: function (data, textStatus, jqXHR) { + setJwtToken(data.token); + $login.hide(); + $notLoggedIn.hide(); + showTokenInformation() + showUserInformation(); + }, + error: function (jqXHR, textStatus, errorThrown) { + if (jqXHR.status === 401) { + $('#loginErrorModal') + .modal("show") + .find(".modal-body") + .empty() + .html("

Spring exception:
" + jqXHR.responseJSON.exception + "

"); + } else { + throw new Error("an unexpected error occured: " + errorThrown); + } + } + }); + } + + function doLogout() { + removeJwtToken(); + $login.show(); + $userInfo + .hide() + .find("#userInfoBody").empty(); + $loggedIn + .hide() + .attr("title", "") + .empty(); + $notLoggedIn.show(); + } + + function createAuthorizationTokenHeader() { + var token = getJwtToken(); + if (token) { + return {"Authorization": token}; + } else { + return {}; + } + } + + function showUserInformation() { + $.ajax({ + url: "/user", + type: "GET", + contentType: "application/json; charset=utf-8", + dataType: "json", + headers: createAuthorizationTokenHeader(), + success: function (data, textStatus, jqXHR) { + var $userInfoBody = $userInfo.find("#userInfoBody"); + + $userInfoBody.append($("
").text("Username: " + data.username)); + $userInfoBody.append($("
").text("Email: " + data.email)); + + var $authorityList = $("
    "); + data.authorities.forEach(function (authorityItem) { + $authorityList.append($("
  • ").text(authorityItem.authority)); + }); + var $authorities = $("
    ").text("Authorities:"); + $authorities.append($authorityList); + + $userInfoBody.append($authorities); + $userInfo.show(); + } + }); + } + + function showTokenInformation() { + $loggedIn + .text("Token: " + getJwtToken()) + .attr("title", "Token: " + getJwtToken()) + .show(); + } + + function showResponse(statusCode, message) { + $response + .empty() + .text("status code: " + statusCode + "\n-------------------------\n" + message); + } + + // REGISTER EVENT LISTENERS ============================================================= + $("#loginForm").submit(function (event) { + event.preventDefault(); + + var $form = $(this); + var formData = { + username: $form.find('input[name="username"]').val(), + password: $form.find('input[name="password"]').val() + }; + + doLogin(formData); + }); + + $("#logoutButton").click(doLogout); + + $("#exampleServiceBtn").click(function () { + $.ajax({ + url: "/api/v1/evaluations/154", + type: "GET", + contentType: "application/json; charset=utf-8", + dataType: "json", + headers: createAuthorizationTokenHeader(), + success: function (data, textStatus, jqXHR) { + showResponse(jqXHR.status, JSON.stringify(data)); + }, + error: function (jqXHR, textStatus, errorThrown) { + showResponse(jqXHR.status, errorThrown); + } + }); + }); + + $("#adminServiceBtn").click(function () { + $.ajax({ + url: "/api/v1/batches/171", + type: "GET", + contentType: "application/json; charset=utf-8", + headers: createAuthorizationTokenHeader(), + success: function (data, textStatus, jqXHR) { + showResponse(jqXHR.status, data); + }, + error: function (jqXHR, textStatus, errorThrown) { + showResponse(jqXHR.status, errorThrown); + } + }); + }); + + $loggedIn.click(function () { + $loggedIn + .toggleClass("text-hidden") + .toggleClass("text-shown"); + }); + + // INITIAL CALLS ============================================================= + if (getJwtToken()) { + $login.hide(); + $notLoggedIn.hide(); + showTokenInformation(); + showUserInformation(); + } +}); \ No newline at end of file From 69623dc65e4d9713e8d76d795459ca67a90b6d84 Mon Sep 17 00:00:00 2001 From: Madison Date: Mon, 17 Apr 2017 09:40:20 -0700 Subject: [PATCH 19/19] reference fix --- .../com/revature/security/extra/JwtAuthenticationResponse.java | 2 +- .../extra/controllers/AuthenticationRestController.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/revature/security/extra/JwtAuthenticationResponse.java b/src/main/java/com/revature/security/extra/JwtAuthenticationResponse.java index 265a882..6c65e7c 100644 --- a/src/main/java/com/revature/security/extra/JwtAuthenticationResponse.java +++ b/src/main/java/com/revature/security/extra/JwtAuthenticationResponse.java @@ -3,7 +3,7 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package com.revature.revatureSecurity; +package com.revature.security.extra; import java.io.Serializable; diff --git a/src/main/java/com/revature/security/extra/controllers/AuthenticationRestController.java b/src/main/java/com/revature/security/extra/controllers/AuthenticationRestController.java index 2464ad2..2361c27 100644 --- a/src/main/java/com/revature/security/extra/controllers/AuthenticationRestController.java +++ b/src/main/java/com/revature/security/extra/controllers/AuthenticationRestController.java @@ -8,7 +8,7 @@ import com.revature.security.JwtAuthenticationRequest; import com.revature.security.extra.JwtTokenUtil; import com.revature.security.extra.JwtUser; -import com.revature.revatureSecurity.JwtAuthenticationResponse; +import com.revature.security.extra.JwtAuthenticationResponse; import javax.servlet.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value;