From c21f381189454617a9646f730ed0fbebb5eafcaa Mon Sep 17 00:00:00 2001 From: Martin Schaaf <703355+mschaaf@users.noreply.github.com> Date: Tue, 8 Jun 2021 19:51:14 +0200 Subject: [PATCH 1/3] weplantaforest #221 - Refactor token handling --- ui/src/js/app.js | 6 +++-- .../WebSecurityConfigurerAdapterExt.java | 5 +++- .../StatelessAuthenticationFilter.java | 18 ++++++++++++--- .../security/TokenAuthenticationService.java | 4 ++-- .../weplantaforest/security/TokenHandler.java | 23 +++++++++++++++---- .../weplantaforest/user/User.java | 5 ++++ 6 files changed, 49 insertions(+), 12 deletions(-) diff --git a/ui/src/js/app.js b/ui/src/js/app.js index 257a33dfd..2b1f9ea61 100644 --- a/ui/src/js/app.js +++ b/ui/src/js/app.js @@ -7,11 +7,13 @@ import '../less/main.less'; import Routes from './routes'; axios.interceptors.response.use( - response => { + (response) => { return response; }, - error => { + (error) => { if (error.response) { + // TODO in case of 401 or invalid token set token to null and isAmdin false + // TODO in any other case store the new token if (error.response.status == 403) { browserHistory.push('/forbidden?calledUrl=' + error.response.config.url); } else if (error.response.status == 402) { diff --git a/user/src/main/java/org/dicadeveloper/weplantaforest/WebSecurityConfigurerAdapterExt.java b/user/src/main/java/org/dicadeveloper/weplantaforest/WebSecurityConfigurerAdapterExt.java index f4eefdfbb..9180b963a 100644 --- a/user/src/main/java/org/dicadeveloper/weplantaforest/WebSecurityConfigurerAdapterExt.java +++ b/user/src/main/java/org/dicadeveloper/weplantaforest/WebSecurityConfigurerAdapterExt.java @@ -31,6 +31,9 @@ public class WebSecurityConfigurerAdapterExt extends WebSecurityConfigurerAdapte @Autowired private TokenAuthenticationService tokenAuthenticationService; + @Autowired + private UserDetailsService userDetailsService; + public WebSecurityConfigurerAdapterExt() { super(true); } @@ -54,7 +57,7 @@ protected void configure(HttpSecurity http) throws Exception { // custom Token based authentication based on the header // previously // given to the client - .addFilterBefore(new StatelessAuthenticationFilter(tokenAuthenticationService), UsernamePasswordAuthenticationFilter.class); + .addFilterBefore(new StatelessAuthenticationFilter(tokenAuthenticationService, userDetailsService), UsernamePasswordAuthenticationFilter.class); } diff --git a/user/src/main/java/org/dicadeveloper/weplantaforest/security/StatelessAuthenticationFilter.java b/user/src/main/java/org/dicadeveloper/weplantaforest/security/StatelessAuthenticationFilter.java index dbcb51c15..1abf38690 100644 --- a/user/src/main/java/org/dicadeveloper/weplantaforest/security/StatelessAuthenticationFilter.java +++ b/user/src/main/java/org/dicadeveloper/weplantaforest/security/StatelessAuthenticationFilter.java @@ -7,7 +7,10 @@ import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.dicadeveloper.weplantaforest.user.User; +import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.filter.GenericFilterBean; @@ -15,13 +18,22 @@ public class StatelessAuthenticationFilter extends GenericFilterBean { private final TokenAuthenticationService tokenAuthenticationService; - public StatelessAuthenticationFilter(TokenAuthenticationService taService) { + private final UserDetailsService userDetailsService; + + public StatelessAuthenticationFilter(TokenAuthenticationService taService, UserDetailsService userDetailsService) { this.tokenAuthenticationService = taService; + this.userDetailsService = userDetailsService; } @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { - SecurityContextHolder.getContext().setAuthentication(tokenAuthenticationService.getAuthentication((HttpServletRequest) req)); - chain.doFilter(req, res); // always continue + final Authentication authentication = tokenAuthenticationService.getAuthentication((HttpServletRequest) req); + SecurityContextHolder.getContext().setAuthentication(authentication); + + if (null != authentication) { + tokenAuthenticationService.addAuthentication((HttpServletResponse) res, authentication); + } + + chain.doFilter(req, res); } } \ No newline at end of file diff --git a/user/src/main/java/org/dicadeveloper/weplantaforest/security/TokenAuthenticationService.java b/user/src/main/java/org/dicadeveloper/weplantaforest/security/TokenAuthenticationService.java index 3e6f5ae95..a537cefd5 100644 --- a/user/src/main/java/org/dicadeveloper/weplantaforest/security/TokenAuthenticationService.java +++ b/user/src/main/java/org/dicadeveloper/weplantaforest/security/TokenAuthenticationService.java @@ -33,8 +33,8 @@ public TokenAuthenticationService(@Value("${token.secret}") String secret, UserS this._userHelper = userHelper; } - public void addAuthentication(HttpServletResponse response, UserAuthentication authentication) { - final User user = authentication.getDetails(); + public void addAuthentication(HttpServletResponse response, Authentication authentication) { + final User user = (User) authentication.getDetails(); response.addHeader(AUTH_HEADER_NAME, tokenHandler.createTokenForUser(user)); response.addHeader(USERNAME_HEADER_NAME, user.getUsername()); } diff --git a/user/src/main/java/org/dicadeveloper/weplantaforest/security/TokenHandler.java b/user/src/main/java/org/dicadeveloper/weplantaforest/security/TokenHandler.java index 73f9dc9c3..d7d80eaf1 100644 --- a/user/src/main/java/org/dicadeveloper/weplantaforest/security/TokenHandler.java +++ b/user/src/main/java/org/dicadeveloper/weplantaforest/security/TokenHandler.java @@ -4,6 +4,8 @@ import java.io.IOException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; +import java.time.LocalDateTime; +import java.time.ZoneOffset; import java.util.Arrays; import javax.crypto.Mac; @@ -15,6 +17,11 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.SneakyThrows; +import lombok.val; +import lombok.extern.slf4j.Slf4j; + +@Slf4j public final class TokenHandler { private static final String HMAC_ALGO = "HmacSHA256"; @@ -41,8 +48,14 @@ public User parseUserFromToken(String token) { boolean validHash = Arrays.equals(createHmac(userBytes), hash); if (validHash) { - final User user = fromJSON(userBytes); - return user; + try { + final User user = fromJSON(userBytes); + if (user.getAuthenticationExpiresAt() == null || LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli() < user.getAuthenticationExpiresAt()) { + return user; + } + } catch (Exception e) { + LOG.warn("authentication token has wrong format. log the user out!!!"); + } } } catch (IllegalArgumentException e) { // log tempering attempt here @@ -69,10 +82,12 @@ private User fromJSON(final byte[] userBytes) { } } + @SneakyThrows private byte[] toJSON(User user) { try { - //TODO: add expiresAt field - return new ObjectMapper().writeValueAsBytes(user); + val mapper = new ObjectMapper(); + user.setAuthenticationExpiresAt(LocalDateTime.now().plusWeeks(1).toInstant(ZoneOffset.UTC).toEpochMilli()); + return mapper.writeValueAsBytes(user); } catch (JsonProcessingException e) { throw new IllegalStateException(e); } diff --git a/user/src/main/java/org/dicadeveloper/weplantaforest/user/User.java b/user/src/main/java/org/dicadeveloper/weplantaforest/user/User.java index 9bfb13b45..87b8e3b5f 100644 --- a/user/src/main/java/org/dicadeveloper/weplantaforest/user/User.java +++ b/user/src/main/java/org/dicadeveloper/weplantaforest/user/User.java @@ -29,6 +29,7 @@ import org.springframework.security.core.userdetails.UserDetails; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonView; import lombok.EqualsAndHashCode; @@ -110,6 +111,10 @@ public class User implements UserDetails { @JsonIgnore private Team team; + @Transient + @JsonProperty("authenticationExpiresAt") + private Long authenticationExpiresAt; + public void addRole(final Role role) { roles.add(role); } From 71cffc73ac1556129d9ddb3bb531638d8471f8e0 Mon Sep 17 00:00:00 2001 From: Martin Schaaf <703355+mschaaf@users.noreply.github.com> Date: Tue, 22 Jun 2021 22:07:19 +0200 Subject: [PATCH 2/3] weplantaforest #221 - Refactor token handling --- .../WebSecurityConfigurerAdapterExt.java | 4 +- .../StatelessAuthenticationFilter.java | 27 ----- .../security/TokenAuthenticationService.java | 60 ---------- .../admin/security/TokenHandler.java | 93 --------------- .../weplantaforest/admin/user/User.java | 10 +- .../admin/cart/CartControllerTest.java | 2 +- .../admin/project/ProjectControllerTest.java | 3 +- .../admin/tree/TreeControllerTest.java | 2 +- .../treeType/TreeTypeControllerTest.java | 2 +- .../admin/user/UserControllerTest.java | 2 +- .../WebSecurityConfigurerAdapterExt.java | 4 +- .../StatelessAuthenticationFilter.java | 27 ----- .../security/TokenAuthenticationService.java | 60 ---------- .../articlemanager/security/TokenHandler.java | 106 ------------------ .../articlemanager/user/User.java | 10 +- common/common.gradle | 3 + .../weplantaforest/common/user/IUser.java | 20 ++++ .../StatelessAuthenticationFilter.java | 6 +- .../security/TokenAuthenticationService.java | 37 ++---- .../weplantaforest/security/TokenHandler.java | 30 ++--- .../security/UserAuthentication.java | 20 ++-- ui/src/js/app.js | 16 ++- .../security/StatelessLoginFilter.java | 3 +- .../weplantaforest/user/User.java | 4 +- user/user.gradle | 2 +- 25 files changed, 96 insertions(+), 457 deletions(-) delete mode 100644 admin/src/main/java/org/dicadeveloper/weplantaforest/admin/security/StatelessAuthenticationFilter.java delete mode 100644 admin/src/main/java/org/dicadeveloper/weplantaforest/admin/security/TokenAuthenticationService.java delete mode 100644 admin/src/main/java/org/dicadeveloper/weplantaforest/admin/security/TokenHandler.java delete mode 100644 article-manager/src/main/java/org/dicadeveloper/weplantaforest/articlemanager/security/StatelessAuthenticationFilter.java delete mode 100644 article-manager/src/main/java/org/dicadeveloper/weplantaforest/articlemanager/security/TokenAuthenticationService.java delete mode 100644 article-manager/src/main/java/org/dicadeveloper/weplantaforest/articlemanager/security/TokenHandler.java create mode 100644 common/src/main/java/org/dicadeveloper/weplantaforest/common/user/IUser.java rename {user => common}/src/main/java/org/dicadeveloper/weplantaforest/security/StatelessAuthenticationFilter.java (85%) rename {user => common}/src/main/java/org/dicadeveloper/weplantaforest/security/TokenAuthenticationService.java (63%) rename {user => common}/src/main/java/org/dicadeveloper/weplantaforest/security/TokenHandler.java (73%) rename {user => common}/src/main/java/org/dicadeveloper/weplantaforest/security/UserAuthentication.java (65%) diff --git a/admin/src/main/java/org/dicadeveloper/weplantaforest/admin/WebSecurityConfigurerAdapterExt.java b/admin/src/main/java/org/dicadeveloper/weplantaforest/admin/WebSecurityConfigurerAdapterExt.java index c6148fe98..7e475bfb6 100644 --- a/admin/src/main/java/org/dicadeveloper/weplantaforest/admin/WebSecurityConfigurerAdapterExt.java +++ b/admin/src/main/java/org/dicadeveloper/weplantaforest/admin/WebSecurityConfigurerAdapterExt.java @@ -1,10 +1,10 @@ package org.dicadeveloper.weplantaforest.admin; import org.dicadeveloper.weplantaforest.admin.security.PasswordEncrypter; -import org.dicadeveloper.weplantaforest.admin.security.StatelessAuthenticationFilter; -import org.dicadeveloper.weplantaforest.admin.security.TokenAuthenticationService; import org.dicadeveloper.weplantaforest.admin.security.UserDetailsService; import org.dicadeveloper.weplantaforest.common.user.Role; +import org.dicadeveloper.weplantaforest.security.StatelessAuthenticationFilter; +import org.dicadeveloper.weplantaforest.security.TokenAuthenticationService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/admin/src/main/java/org/dicadeveloper/weplantaforest/admin/security/StatelessAuthenticationFilter.java b/admin/src/main/java/org/dicadeveloper/weplantaforest/admin/security/StatelessAuthenticationFilter.java deleted file mode 100644 index 2cb4e6715..000000000 --- a/admin/src/main/java/org/dicadeveloper/weplantaforest/admin/security/StatelessAuthenticationFilter.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.dicadeveloper.weplantaforest.admin.security; - -import java.io.IOException; - -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; - -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.web.filter.GenericFilterBean; - -public class StatelessAuthenticationFilter extends GenericFilterBean { - - private final TokenAuthenticationService tokenAuthenticationService; - - public StatelessAuthenticationFilter(TokenAuthenticationService taService) { - this.tokenAuthenticationService = taService; - } - - @Override - public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { - SecurityContextHolder.getContext().setAuthentication(tokenAuthenticationService.getAuthentication((HttpServletRequest) req)); - chain.doFilter(req, res); // always continue - } -} \ No newline at end of file diff --git a/admin/src/main/java/org/dicadeveloper/weplantaforest/admin/security/TokenAuthenticationService.java b/admin/src/main/java/org/dicadeveloper/weplantaforest/admin/security/TokenAuthenticationService.java deleted file mode 100644 index 4356273b5..000000000 --- a/admin/src/main/java/org/dicadeveloper/weplantaforest/admin/security/TokenAuthenticationService.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.dicadeveloper.weplantaforest.admin.security; - -import javax.servlet.http.HttpServletRequest; -import javax.xml.bind.DatatypeConverter; - -import org.dicadeveloper.weplantaforest.admin.user.User; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.PropertySource; -import org.springframework.security.core.Authentication; -import org.springframework.stereotype.Service; - -@Service -@PropertySource(value = { "classpath:application.properties" }) -public class TokenAuthenticationService { - - private static final String AUTH_HEADER_NAME = "X-AUTH-TOKEN"; - - private final TokenHandler tokenHandler; - - @Autowired - public TokenAuthenticationService(@Value("${token.secret}") String secret) { - tokenHandler = new TokenHandler(DatatypeConverter.parseBase64Binary(secret)); - } - - public Authentication getAuthentication(HttpServletRequest request) { - final String token = request.getHeader(AUTH_HEADER_NAME); - if (token != null) { - final User user = tokenHandler.parseUserFromToken(token); - if (user != null) { - return new UserAuthentication(user); - } - } - return null; - } - - public String getTokenFromUser(User user) { - if (user != null) { - final String token = tokenHandler.createTokenForUser(user); - return token; - } - return null; - } - - public User getUserFromToken(String userToken) { - if (userToken != null) { - final User user = tokenHandler.parseUserFromToken(userToken); - return user; - } - return null; - } - - public boolean isAdmin(String userToken) { - if (userToken != "") { - final User user = tokenHandler.parseUserFromToken(userToken); - return user.isAdmin(); - } - return false; - } -} diff --git a/admin/src/main/java/org/dicadeveloper/weplantaforest/admin/security/TokenHandler.java b/admin/src/main/java/org/dicadeveloper/weplantaforest/admin/security/TokenHandler.java deleted file mode 100644 index f76016b1a..000000000 --- a/admin/src/main/java/org/dicadeveloper/weplantaforest/admin/security/TokenHandler.java +++ /dev/null @@ -1,93 +0,0 @@ -package org.dicadeveloper.weplantaforest.admin.security; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.util.Arrays; - -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; -import javax.xml.bind.DatatypeConverter; - -import org.dicadeveloper.weplantaforest.admin.user.User; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; - -public final class TokenHandler { - - private static final String HMAC_ALGO = "HmacSHA256"; - private static final String SEPARATOR = "."; - private static final String SEPARATOR_SPLITTER = "\\."; - - private final Mac hmac; - - public TokenHandler(byte[] secretKey) { - try { - hmac = Mac.getInstance(HMAC_ALGO); - hmac.init(new SecretKeySpec(secretKey, HMAC_ALGO)); - } catch (NoSuchAlgorithmException | InvalidKeyException e) { - throw new IllegalStateException("failed to initialize HMAC: " + e.getMessage(), e); - } - } - - public User parseUserFromToken(String token) { - final String[] parts = token.split(SEPARATOR_SPLITTER); - if (parts.length == 2 && parts[0].length() > 0 && parts[1].length() > 0) { - try { - final byte[] userBytes = fromBase64(parts[0]); - final byte[] hash = fromBase64(parts[1]); - - boolean validHash = Arrays.equals(createHmac(userBytes), hash); - if (validHash) { - final User user = fromJSON(userBytes); - return user; - } - } catch (IllegalArgumentException e) { - // log tempering attempt here - } - } - return null; - } - - public String createTokenForUser(User user) { - byte[] userBytes = toJSON(user); - byte[] hash = createHmac(userBytes); - final StringBuilder sb = new StringBuilder(170); - sb.append(toBase64(userBytes)); - sb.append(SEPARATOR); - sb.append(toBase64(hash)); - return sb.toString(); - } - - private User fromJSON(final byte[] userBytes) { - try { - return new ObjectMapper().readValue(new ByteArrayInputStream(userBytes), User.class); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } - - private byte[] toJSON(User user) { - try { - return new ObjectMapper().writeValueAsBytes(user); - } catch (JsonProcessingException e) { - throw new IllegalStateException(e); - } - } - - private String toBase64(byte[] content) { - return DatatypeConverter.printBase64Binary(content); - } - - private byte[] fromBase64(String content) { - return DatatypeConverter.parseBase64Binary(content); - } - - // synchronized to guard internal hmac object - private synchronized byte[] createHmac(byte[] content) { - return hmac.doFinal(content); - } - -} diff --git a/admin/src/main/java/org/dicadeveloper/weplantaforest/admin/user/User.java b/admin/src/main/java/org/dicadeveloper/weplantaforest/admin/user/User.java index 6a609f747..7dbd729e1 100644 --- a/admin/src/main/java/org/dicadeveloper/weplantaforest/admin/user/User.java +++ b/admin/src/main/java/org/dicadeveloper/weplantaforest/admin/user/User.java @@ -18,16 +18,19 @@ import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; +import javax.persistence.Transient; import org.dicadeveloper.weplantaforest.admin.team.Team; import org.dicadeveloper.weplantaforest.admin.views.Views; import org.dicadeveloper.weplantaforest.common.support.Language; +import org.dicadeveloper.weplantaforest.common.user.IUser; import org.dicadeveloper.weplantaforest.common.user.Role; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonView; import lombok.EqualsAndHashCode; @@ -39,7 +42,7 @@ @Setter @EqualsAndHashCode @Table(name = "User") -public class User implements UserDetails { +public class User implements UserDetails, IUser { /** * @@ -114,6 +117,10 @@ public class User implements UserDetails { @Column(name = "ELEMENT") private Set roles = new HashSet(); + @Transient + @JsonProperty("authenticationExpiresAt") + private Long authenticationExpiresAt; + public void addRole(final Role role) { roles.add(role); } @@ -126,6 +133,7 @@ public boolean hasRole(Role role) { return roles.contains(role); } + @Override @JsonView(Views.OverviewUser.class) public boolean isAdmin() { return roles.contains(Role.ADMIN); diff --git a/admin/src/test/java/org/dicadeveloper/weplantaforest/admin/cart/CartControllerTest.java b/admin/src/test/java/org/dicadeveloper/weplantaforest/admin/cart/CartControllerTest.java index be355cd3c..4a5e05ace 100644 --- a/admin/src/test/java/org/dicadeveloper/weplantaforest/admin/cart/CartControllerTest.java +++ b/admin/src/test/java/org/dicadeveloper/weplantaforest/admin/cart/CartControllerTest.java @@ -12,7 +12,6 @@ import javax.transaction.Transactional; import org.dicadeveloper.weplantaforest.admin.project.Project; -import org.dicadeveloper.weplantaforest.admin.security.TokenAuthenticationService; import org.dicadeveloper.weplantaforest.admin.support.Uris; import org.dicadeveloper.weplantaforest.admin.testSupport.DbInjecter; import org.dicadeveloper.weplantaforest.admin.tree.TreeRepository; @@ -21,6 +20,7 @@ import org.dicadeveloper.weplantaforest.admin.user.UserRepository; import org.dicadeveloper.weplantaforest.common.testsupport.CleanDbRule; import org.dicadeveloper.weplantaforest.common.testsupport.TestUtil; +import org.dicadeveloper.weplantaforest.security.TokenAuthenticationService; import org.junit.Before; import org.junit.Rule; import org.junit.Test; diff --git a/admin/src/test/java/org/dicadeveloper/weplantaforest/admin/project/ProjectControllerTest.java b/admin/src/test/java/org/dicadeveloper/weplantaforest/admin/project/ProjectControllerTest.java index ddd9ff2ba..79cd4b803 100644 --- a/admin/src/test/java/org/dicadeveloper/weplantaforest/admin/project/ProjectControllerTest.java +++ b/admin/src/test/java/org/dicadeveloper/weplantaforest/admin/project/ProjectControllerTest.java @@ -14,7 +14,6 @@ import javax.transaction.Transactional; import org.dicadeveloper.weplantaforest.admin.FileSystemInjector; -import org.dicadeveloper.weplantaforest.admin.security.TokenAuthenticationService; import org.dicadeveloper.weplantaforest.admin.support.Uris; import org.dicadeveloper.weplantaforest.admin.testSupport.DbInjecter; import org.dicadeveloper.weplantaforest.admin.treeType.TreeType; @@ -22,6 +21,8 @@ import org.dicadeveloper.weplantaforest.admin.user.UserRepository; import org.dicadeveloper.weplantaforest.common.testsupport.CleanDbRule; import org.dicadeveloper.weplantaforest.common.testsupport.TestUtil; +import org.dicadeveloper.weplantaforest.security.TokenAuthenticationService; +import org.dicadeveloper.weplantaforest.security.TokenAuthenticationService; import org.junit.Before; import org.junit.Rule; import org.junit.Test; diff --git a/admin/src/test/java/org/dicadeveloper/weplantaforest/admin/tree/TreeControllerTest.java b/admin/src/test/java/org/dicadeveloper/weplantaforest/admin/tree/TreeControllerTest.java index 85e7127d2..64abad6f4 100644 --- a/admin/src/test/java/org/dicadeveloper/weplantaforest/admin/tree/TreeControllerTest.java +++ b/admin/src/test/java/org/dicadeveloper/weplantaforest/admin/tree/TreeControllerTest.java @@ -6,7 +6,6 @@ import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup; import org.dicadeveloper.weplantaforest.admin.project.Project; -import org.dicadeveloper.weplantaforest.admin.security.TokenAuthenticationService; import org.dicadeveloper.weplantaforest.admin.support.Uris; import org.dicadeveloper.weplantaforest.admin.testSupport.DbInjecter; import org.dicadeveloper.weplantaforest.admin.treeType.TreeType; @@ -14,6 +13,7 @@ import org.dicadeveloper.weplantaforest.admin.user.UserRepository; import org.dicadeveloper.weplantaforest.common.testsupport.CleanDbRule; import org.dicadeveloper.weplantaforest.common.testsupport.TestUtil; +import org.dicadeveloper.weplantaforest.security.TokenAuthenticationService; import org.junit.Before; import org.junit.Rule; import org.junit.Test; diff --git a/admin/src/test/java/org/dicadeveloper/weplantaforest/admin/treeType/TreeTypeControllerTest.java b/admin/src/test/java/org/dicadeveloper/weplantaforest/admin/treeType/TreeTypeControllerTest.java index 8efbb4acf..cd8b81910 100644 --- a/admin/src/test/java/org/dicadeveloper/weplantaforest/admin/treeType/TreeTypeControllerTest.java +++ b/admin/src/test/java/org/dicadeveloper/weplantaforest/admin/treeType/TreeTypeControllerTest.java @@ -10,12 +10,12 @@ import java.io.IOException; import org.dicadeveloper.weplantaforest.admin.FileSystemInjector; -import org.dicadeveloper.weplantaforest.admin.security.TokenAuthenticationService; import org.dicadeveloper.weplantaforest.admin.support.Uris; import org.dicadeveloper.weplantaforest.admin.testSupport.DbInjecter; import org.dicadeveloper.weplantaforest.admin.user.UserRepository; import org.dicadeveloper.weplantaforest.common.testsupport.CleanDbRule; import org.dicadeveloper.weplantaforest.common.testsupport.TestUtil; +import org.dicadeveloper.weplantaforest.security.TokenAuthenticationService; import org.junit.After; import org.junit.Before; import org.junit.Rule; diff --git a/admin/src/test/java/org/dicadeveloper/weplantaforest/admin/user/UserControllerTest.java b/admin/src/test/java/org/dicadeveloper/weplantaforest/admin/user/UserControllerTest.java index a5d566169..333ce799d 100644 --- a/admin/src/test/java/org/dicadeveloper/weplantaforest/admin/user/UserControllerTest.java +++ b/admin/src/test/java/org/dicadeveloper/weplantaforest/admin/user/UserControllerTest.java @@ -5,9 +5,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup; -import org.dicadeveloper.weplantaforest.admin.security.TokenAuthenticationService; import org.dicadeveloper.weplantaforest.admin.testSupport.DbInjecter; import org.dicadeveloper.weplantaforest.common.testsupport.CleanDbRule; +import org.dicadeveloper.weplantaforest.security.TokenAuthenticationService; import org.junit.Before; import org.junit.Rule; import org.junit.Test; diff --git a/article-manager/src/main/java/org/dicadeveloper/weplantaforest/articlemanager/WebSecurityConfigurerAdapterExt.java b/article-manager/src/main/java/org/dicadeveloper/weplantaforest/articlemanager/WebSecurityConfigurerAdapterExt.java index 9a84bdc7c..e45568ec6 100644 --- a/article-manager/src/main/java/org/dicadeveloper/weplantaforest/articlemanager/WebSecurityConfigurerAdapterExt.java +++ b/article-manager/src/main/java/org/dicadeveloper/weplantaforest/articlemanager/WebSecurityConfigurerAdapterExt.java @@ -1,10 +1,10 @@ package org.dicadeveloper.weplantaforest.articlemanager; import org.dicadeveloper.weplantaforest.articlemanager.security.PasswordEncrypter; -import org.dicadeveloper.weplantaforest.articlemanager.security.StatelessAuthenticationFilter; -import org.dicadeveloper.weplantaforest.articlemanager.security.TokenAuthenticationService; import org.dicadeveloper.weplantaforest.articlemanager.security.UserDetailsService; import org.dicadeveloper.weplantaforest.common.user.Role; +import org.dicadeveloper.weplantaforest.security.StatelessAuthenticationFilter; +import org.dicadeveloper.weplantaforest.security.TokenAuthenticationService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/article-manager/src/main/java/org/dicadeveloper/weplantaforest/articlemanager/security/StatelessAuthenticationFilter.java b/article-manager/src/main/java/org/dicadeveloper/weplantaforest/articlemanager/security/StatelessAuthenticationFilter.java deleted file mode 100644 index 6c6626773..000000000 --- a/article-manager/src/main/java/org/dicadeveloper/weplantaforest/articlemanager/security/StatelessAuthenticationFilter.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.dicadeveloper.weplantaforest.articlemanager.security; - -import java.io.IOException; - -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; - -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.web.filter.GenericFilterBean; - -public class StatelessAuthenticationFilter extends GenericFilterBean { - - private final TokenAuthenticationService tokenAuthenticationService; - - public StatelessAuthenticationFilter(TokenAuthenticationService taService) { - this.tokenAuthenticationService = taService; - } - - @Override - public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { - SecurityContextHolder.getContext().setAuthentication(tokenAuthenticationService.getAuthentication((HttpServletRequest) req)); - chain.doFilter(req, res); // always continue - } -} \ No newline at end of file diff --git a/article-manager/src/main/java/org/dicadeveloper/weplantaforest/articlemanager/security/TokenAuthenticationService.java b/article-manager/src/main/java/org/dicadeveloper/weplantaforest/articlemanager/security/TokenAuthenticationService.java deleted file mode 100644 index 73b4a4940..000000000 --- a/article-manager/src/main/java/org/dicadeveloper/weplantaforest/articlemanager/security/TokenAuthenticationService.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.dicadeveloper.weplantaforest.articlemanager.security; - -import javax.servlet.http.HttpServletRequest; -import javax.xml.bind.DatatypeConverter; - -import org.dicadeveloper.weplantaforest.articlemanager.user.User; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.PropertySource; -import org.springframework.security.core.Authentication; -import org.springframework.stereotype.Service; - -@Service -@PropertySource(value = { "classpath:application.properties" }) -public class TokenAuthenticationService { - - private static final String AUTH_HEADER_NAME = "X-AUTH-TOKEN"; - - private final TokenHandler tokenHandler; - - @Autowired - public TokenAuthenticationService(@Value("${token.secret}") String secret) { - tokenHandler = new TokenHandler(DatatypeConverter.parseBase64Binary(secret)); - } - - public Authentication getAuthentication(HttpServletRequest request) { - final String token = request.getHeader(AUTH_HEADER_NAME); - if (token != null) { - final User user = tokenHandler.parseUserFromToken(token); - if (user != null) { - return new UserAuthentication(user); - } - } - return null; - } - - public String getTokenFromUser(User user) { - if (user != null) { - final String token = tokenHandler.createTokenForUser(user); - return token; - } - return null; - } - - public User getUserFromToken(String userToken) { - if (userToken != null) { - final User user = tokenHandler.parseUserFromToken(userToken); - return user; - } - return null; - } - - public boolean isAdmin(String userToken) { - if (userToken != "") { - final User user = tokenHandler.parseUserFromToken(userToken); - return user.isAdmin(); - } - return false; - } -} diff --git a/article-manager/src/main/java/org/dicadeveloper/weplantaforest/articlemanager/security/TokenHandler.java b/article-manager/src/main/java/org/dicadeveloper/weplantaforest/articlemanager/security/TokenHandler.java deleted file mode 100644 index c641df008..000000000 --- a/article-manager/src/main/java/org/dicadeveloper/weplantaforest/articlemanager/security/TokenHandler.java +++ /dev/null @@ -1,106 +0,0 @@ -package org.dicadeveloper.weplantaforest.articlemanager.security; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.util.Arrays; - -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; -import javax.xml.bind.DatatypeConverter; - -import org.dicadeveloper.weplantaforest.articlemanager.user.User; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; - -public final class TokenHandler { - - private static final String HMAC_ALGO = "HmacSHA256"; - private static final String SEPARATOR = "."; - private static final String SEPARATOR_SPLITTER = "\\."; - - private final Mac hmac; - - public TokenHandler(byte[] secretKey) { - try { - hmac = Mac.getInstance(HMAC_ALGO); - hmac.init(new SecretKeySpec(secretKey, HMAC_ALGO)); - } catch (NoSuchAlgorithmException | InvalidKeyException e) { - throw new IllegalStateException("failed to initialize HMAC: " + e.getMessage(), e); - } - } - - public User parseUserFromToken(String token) { - final String[] parts = token.split(SEPARATOR_SPLITTER); - if (parts.length == 2 && parts[0].length() > 0 && parts[1].length() > 0) { - try { - final byte[] userBytes = fromBase64(parts[0]); - final byte[] hash = fromBase64(parts[1]); - - boolean validHash = Arrays.equals(createHmac(userBytes), hash); - if (validHash) { - final User user = fromJSON(userBytes); - return user; - } - } catch (IllegalArgumentException e) { - // log tempering attempt here - } - } - return null; - } - - public String createTokenForUser(User user) { - byte[] userBytes = toJSON(user); - byte[] hash = createHmac(userBytes); - final StringBuilder sb = new StringBuilder(170); - sb.append(toBase64(userBytes)); - sb.append(SEPARATOR); - sb.append(toBase64(hash)); - return sb.toString(); - } - - private User fromJSON(final byte[] userBytes) { - try { - return new ObjectMapper().readValue(new ByteArrayInputStream(userBytes), User.class); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } - - private byte[] toJSON(User user) { - try { - return new ObjectMapper().writeValueAsBytes(user); - } catch (JsonProcessingException e) { - throw new IllegalStateException(e); - } - } - - private String toBase64(byte[] content) { - return DatatypeConverter.printBase64Binary(content); - } - - private byte[] fromBase64(String content) { - return DatatypeConverter.parseBase64Binary(content); - } - - // synchronized to guard internal hmac object - private synchronized byte[] createHmac(byte[] content) { - return hmac.doFinal(content); - } - /* - * public static void main(String[] args) { Date start = new Date(); byte[] - * secret = new byte[70]; new - * java.security.SecureRandom().nextBytes(secret); - * - * TokenHandler tokenHandler = new TokenHandler(secret); for (int i = 0; i < - * 1000; i++) { final User user = new - * User(java.util.UUID.randomUUID().toString().substring(0, 8), new Date( - * new Date().getTime() + 10000)); user.grantRole(UserRole.ADMIN); final - * String token = tokenHandler.createTokenForUser(user); final User - * parsedUser = tokenHandler.parseUserFromToken(token); if (parsedUser == - * null || parsedUser.getUsername() == null) { System.out.println("error"); - * } } System.out.println(System.currentTimeMillis() - start.getTime()); } - */ -} diff --git a/article-manager/src/main/java/org/dicadeveloper/weplantaforest/articlemanager/user/User.java b/article-manager/src/main/java/org/dicadeveloper/weplantaforest/articlemanager/user/User.java index 460fc7a0a..7881f29bc 100644 --- a/article-manager/src/main/java/org/dicadeveloper/weplantaforest/articlemanager/user/User.java +++ b/article-manager/src/main/java/org/dicadeveloper/weplantaforest/articlemanager/user/User.java @@ -17,15 +17,18 @@ import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.Table; +import javax.persistence.Transient; import org.dicadeveloper.weplantaforest.articlemanager.views.Views; import org.dicadeveloper.weplantaforest.common.support.Language; +import org.dicadeveloper.weplantaforest.common.user.IUser; import org.dicadeveloper.weplantaforest.common.user.Role; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonView; import lombok.EqualsAndHashCode; @@ -37,7 +40,7 @@ @Setter @EqualsAndHashCode @Table(name = "User") -public class User implements UserDetails { +public class User implements UserDetails, IUser { /** * @@ -104,6 +107,11 @@ public class User implements UserDetails { @Column(name = "ELEMENT") private Set roles = new HashSet(); + @Transient + @JsonProperty("authenticationExpiresAt") + private Long authenticationExpiresAt; + + @Override public boolean isAdmin() { return roles.contains(Role.ADMIN); } diff --git a/common/common.gradle b/common/common.gradle index 8bf50e0cf..8e1777773 100644 --- a/common/common.gradle +++ b/common/common.gradle @@ -7,12 +7,15 @@ dependencies { compileOnly 'org.projectlombok:lombok:1.18.10' + implementation 'javax.xml.bind:jaxb-api:2.3.1' implementation 'net.coobird:thumbnailator:0.4.8' //mail API implementation 'com.sun.mail:javax.mail:1.6.2' implementation 'org.springframework.boot:spring-boot-starter-web:' + springBootVersion + implementation('org.springframework.boot:spring-boot-starter-security:' + springBootVersion) + testImplementation group: 'junit', name: 'junit', version: '4.12' testImplementation group: 'org.assertj', name: 'assertj-core', version: '3.14.0' } diff --git a/common/src/main/java/org/dicadeveloper/weplantaforest/common/user/IUser.java b/common/src/main/java/org/dicadeveloper/weplantaforest/common/user/IUser.java new file mode 100644 index 000000000..3c904f91e --- /dev/null +++ b/common/src/main/java/org/dicadeveloper/weplantaforest/common/user/IUser.java @@ -0,0 +1,20 @@ +package org.dicadeveloper.weplantaforest.common.user; + +import java.util.Collection; + +import org.springframework.security.core.GrantedAuthority; + +public interface IUser { + + void setAuthenticationExpiresAt(Long expirationInMilliseconds); + + Long getAuthenticationExpiresAt(); + + String getName(); + + boolean isAdmin(); + + Collection getAuthorities(); + + String getPassword(); +} diff --git a/user/src/main/java/org/dicadeveloper/weplantaforest/security/StatelessAuthenticationFilter.java b/common/src/main/java/org/dicadeveloper/weplantaforest/security/StatelessAuthenticationFilter.java similarity index 85% rename from user/src/main/java/org/dicadeveloper/weplantaforest/security/StatelessAuthenticationFilter.java rename to common/src/main/java/org/dicadeveloper/weplantaforest/security/StatelessAuthenticationFilter.java index 1abf38690..584c7827d 100644 --- a/user/src/main/java/org/dicadeveloper/weplantaforest/security/StatelessAuthenticationFilter.java +++ b/common/src/main/java/org/dicadeveloper/weplantaforest/security/StatelessAuthenticationFilter.java @@ -9,7 +9,6 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.dicadeveloper.weplantaforest.user.User; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.filter.GenericFilterBean; @@ -18,11 +17,8 @@ public class StatelessAuthenticationFilter extends GenericFilterBean { private final TokenAuthenticationService tokenAuthenticationService; - private final UserDetailsService userDetailsService; - - public StatelessAuthenticationFilter(TokenAuthenticationService taService, UserDetailsService userDetailsService) { + public StatelessAuthenticationFilter(TokenAuthenticationService taService) { this.tokenAuthenticationService = taService; - this.userDetailsService = userDetailsService; } @Override diff --git a/user/src/main/java/org/dicadeveloper/weplantaforest/security/TokenAuthenticationService.java b/common/src/main/java/org/dicadeveloper/weplantaforest/security/TokenAuthenticationService.java similarity index 63% rename from user/src/main/java/org/dicadeveloper/weplantaforest/security/TokenAuthenticationService.java rename to common/src/main/java/org/dicadeveloper/weplantaforest/security/TokenAuthenticationService.java index a537cefd5..08d71802e 100644 --- a/user/src/main/java/org/dicadeveloper/weplantaforest/security/TokenAuthenticationService.java +++ b/common/src/main/java/org/dicadeveloper/weplantaforest/security/TokenAuthenticationService.java @@ -4,45 +4,36 @@ import javax.servlet.http.HttpServletResponse; import javax.xml.bind.DatatypeConverter; -import org.dicadeveloper.weplantaforest.common.errorhandling.IpatException; -import org.dicadeveloper.weplantaforest.user.User; -import org.dicadeveloper.weplantaforest.user.UserService; +import org.dicadeveloper.weplantaforest.common.user.IUser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.core.Authentication; import org.springframework.stereotype.Service; -import lombok.NonNull; - @Service public class TokenAuthenticationService { private static final String AUTH_HEADER_NAME = "X-AUTH-TOKEN"; - private final static String ANONYMOUS_TOKEN = "anonym-user"; - private static final String USERNAME_HEADER_NAME = "X-AUTH-USERNAME"; private final TokenHandler tokenHandler; - private @NonNull UserService _userHelper; - @Autowired - public TokenAuthenticationService(@Value("${token.secret}") String secret, UserService userHelper) { + public TokenAuthenticationService(@Value("${token.secret}") String secret) { tokenHandler = new TokenHandler(DatatypeConverter.parseBase64Binary(secret)); - this._userHelper = userHelper; } public void addAuthentication(HttpServletResponse response, Authentication authentication) { - final User user = (User) authentication.getDetails(); + final IUser user = (IUser) authentication.getDetails(); response.addHeader(AUTH_HEADER_NAME, tokenHandler.createTokenForUser(user)); - response.addHeader(USERNAME_HEADER_NAME, user.getUsername()); + response.addHeader(USERNAME_HEADER_NAME, user.getName()); } public Authentication getAuthentication(HttpServletRequest request) { final String token = request.getHeader(AUTH_HEADER_NAME); if (token != null) { - final User user = tokenHandler.parseUserFromToken(token); + final IUser user = tokenHandler.parseUserFromToken(token); if (user != null) { return new UserAuthentication(user); } @@ -50,24 +41,14 @@ public Authentication getAuthentication(HttpServletRequest request) { return null; } - public User getUserFromToken(String userToken) { + public IUser getUserFromToken(String userToken) { if (userToken != null) { return tokenHandler.parseUserFromToken(userToken); } return null; } - public User getBuyer(String userToken) throws IpatException { - User buyer = getUserFromToken(userToken); - if (buyer != null) { - } else if (userToken.equals(ANONYMOUS_TOKEN)) { - buyer = _userHelper.createAnonymous(); - } - return buyer; - - } - - public String getTokenFromUser(User user) { + public String getTokenFromUser(IUser user) { if (user != null) { final String token = tokenHandler.createTokenForUser(user); return token; @@ -77,7 +58,7 @@ public String getTokenFromUser(User user) { public boolean isAuthenticatedUser(String userToken, String userName) { if (userToken != "") { - final User user = tokenHandler.parseUserFromToken(userToken); + final IUser user = tokenHandler.parseUserFromToken(userToken); if (user != null && user.getName().equals(userName)) { return true; } @@ -87,7 +68,7 @@ public boolean isAuthenticatedUser(String userToken, String userName) { public boolean isAdmin(String userToken) { if (userToken != "") { - final User user = tokenHandler.parseUserFromToken(userToken); + final IUser user = tokenHandler.parseUserFromToken(userToken); return user.isAdmin(); } return false; diff --git a/user/src/main/java/org/dicadeveloper/weplantaforest/security/TokenHandler.java b/common/src/main/java/org/dicadeveloper/weplantaforest/security/TokenHandler.java similarity index 73% rename from user/src/main/java/org/dicadeveloper/weplantaforest/security/TokenHandler.java rename to common/src/main/java/org/dicadeveloper/weplantaforest/security/TokenHandler.java index d7d80eaf1..d023b95bd 100644 --- a/user/src/main/java/org/dicadeveloper/weplantaforest/security/TokenHandler.java +++ b/common/src/main/java/org/dicadeveloper/weplantaforest/security/TokenHandler.java @@ -12,7 +12,7 @@ import javax.crypto.spec.SecretKeySpec; import javax.xml.bind.DatatypeConverter; -import org.dicadeveloper.weplantaforest.user.User; +import org.dicadeveloper.weplantaforest.common.user.IUser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; @@ -39,7 +39,7 @@ public TokenHandler(byte[] secretKey) { } } - public User parseUserFromToken(String token) { + public IUser parseUserFromToken(String token) { final String[] parts = token.split(SEPARATOR_SPLITTER); if (parts.length == 2 && parts[0].length() > 0 && parts[1].length() > 0) { try { @@ -49,7 +49,7 @@ public User parseUserFromToken(String token) { boolean validHash = Arrays.equals(createHmac(userBytes), hash); if (validHash) { try { - final User user = fromJSON(userBytes); + final IUser user = fromJSON(userBytes); if (user.getAuthenticationExpiresAt() == null || LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli() < user.getAuthenticationExpiresAt()) { return user; } @@ -64,7 +64,7 @@ public User parseUserFromToken(String token) { return null; } - public String createTokenForUser(User user) { + public String createTokenForUser(IUser user) { byte[] userBytes = toJSON(user); byte[] hash = createHmac(userBytes); final StringBuilder sb = new StringBuilder(170); @@ -74,19 +74,19 @@ public String createTokenForUser(User user) { return sb.toString(); } - private User fromJSON(final byte[] userBytes) { + private IUser fromJSON(final byte[] userBytes) { try { - return new ObjectMapper().readValue(new ByteArrayInputStream(userBytes), User.class); + return new ObjectMapper().readValue(new ByteArrayInputStream(userBytes), IUser.class); } catch (IOException e) { throw new IllegalStateException(e); } } @SneakyThrows - private byte[] toJSON(User user) { + private byte[] toJSON(IUser user) { try { val mapper = new ObjectMapper(); - user.setAuthenticationExpiresAt(LocalDateTime.now().plusWeeks(1).toInstant(ZoneOffset.UTC).toEpochMilli()); + user.setAuthenticationExpiresAt(LocalDateTime.now().plusMonths(1).toInstant(ZoneOffset.UTC).toEpochMilli()); return mapper.writeValueAsBytes(user); } catch (JsonProcessingException e) { throw new IllegalStateException(e); @@ -105,18 +105,4 @@ private byte[] fromBase64(String content) { private synchronized byte[] createHmac(byte[] content) { return hmac.doFinal(content); } - /* - * public static void main(String[] args) { Date start = new Date(); byte[] - * secret = new byte[70]; new - * java.security.SecureRandom().nextBytes(secret); - * - * TokenHandler tokenHandler = new TokenHandler(secret); for (int i = 0; i < - * 1000; i++) { final User user = new - * User(java.util.UUID.randomUUID().toString().substring(0, 8), new Date( - * new Date().getTime() + 10000)); user.grantRole(UserRole.ADMIN); final - * String token = tokenHandler.createTokenForUser(user); final User - * parsedUser = tokenHandler.parseUserFromToken(token); if (parsedUser == - * null || parsedUser.getUsername() == null) { System.out.println("error"); - * } } System.out.println(System.currentTimeMillis() - start.getTime()); } - */ } diff --git a/user/src/main/java/org/dicadeveloper/weplantaforest/security/UserAuthentication.java b/common/src/main/java/org/dicadeveloper/weplantaforest/security/UserAuthentication.java similarity index 65% rename from user/src/main/java/org/dicadeveloper/weplantaforest/security/UserAuthentication.java rename to common/src/main/java/org/dicadeveloper/weplantaforest/security/UserAuthentication.java index 6ccde0721..d57668946 100644 --- a/user/src/main/java/org/dicadeveloper/weplantaforest/security/UserAuthentication.java +++ b/common/src/main/java/org/dicadeveloper/weplantaforest/security/UserAuthentication.java @@ -2,23 +2,23 @@ import java.util.Collection; -import org.dicadeveloper.weplantaforest.user.User; +import org.dicadeveloper.weplantaforest.common.user.IUser; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; public class UserAuthentication implements Authentication { private static final long serialVersionUID = -2242106351785882988L; - private final User user; + private final IUser user; private boolean authenticated = true; - public UserAuthentication(User user) { + public UserAuthentication(IUser user) { this.user = user; } @Override public String getName() { - return user.getUsername(); + return user.getName(); } @Override @@ -32,19 +32,13 @@ public Object getCredentials() { } @Override - public User getDetails() { - User customUser = new User(); - customUser.setId(user.getId()); - customUser.setName(user.getName()); - customUser.setMail(user.getMail()); - customUser.setRoles(user.getRoles()); - customUser.setLang(user.getLang()); - return customUser; + public IUser getDetails() { + return user; } @Override public Object getPrincipal() { - return user.getUsername(); + return user.getName(); } @Override diff --git a/ui/src/js/app.js b/ui/src/js/app.js index 2b1f9ea61..84c4999a0 100644 --- a/ui/src/js/app.js +++ b/ui/src/js/app.js @@ -6,19 +6,31 @@ import '../js/common/header/header.less'; import '../less/main.less'; import Routes from './routes'; +function storeToken(response) { + if (response.headers['x-auth-token']) { + let token = response.headers['x-auth-token']; + localStorage.setItem('jwt', token); + } +} + axios.interceptors.response.use( (response) => { + storeToken(response); return response; }, (error) => { if (error.response) { - // TODO in case of 401 or invalid token set token to null and isAmdin false - // TODO in any other case store the new token if (error.response.status == 403) { browserHistory.push('/forbidden?calledUrl=' + error.response.config.url); } else if (error.response.status == 402) { location.href = error.response.data; + } else if (error.response.status == 401) { + localStorage.setItem('jwt', ''); + localStorage.setItem('username', ''); + localStorage.setItem('userDetails', ''); + localStorage.setItem('isAdmin', false); } + storeToken(error.response); } else { console.log(error); } diff --git a/user/src/main/java/org/dicadeveloper/weplantaforest/security/StatelessLoginFilter.java b/user/src/main/java/org/dicadeveloper/weplantaforest/security/StatelessLoginFilter.java index 811ebfbe0..df888f680 100644 --- a/user/src/main/java/org/dicadeveloper/weplantaforest/security/StatelessLoginFilter.java +++ b/user/src/main/java/org/dicadeveloper/weplantaforest/security/StatelessLoginFilter.java @@ -7,6 +7,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.dicadeveloper.weplantaforest.common.user.IUser; import org.dicadeveloper.weplantaforest.user.User; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; @@ -52,7 +53,7 @@ protected void successfulAuthentication(HttpServletRequest request, HttpServletR // Lookup the complete User object from the database and create an // Authentication for it - final User authenticatedUser = userDetailsService.loadUserByUsername(authentication.getName()); + final IUser authenticatedUser = userDetailsService.loadUserByUsername(authentication.getName()); final UserAuthentication userAuthentication = new UserAuthentication(authenticatedUser); // Add the custom token as HTTP header to the response diff --git a/user/src/main/java/org/dicadeveloper/weplantaforest/user/User.java b/user/src/main/java/org/dicadeveloper/weplantaforest/user/User.java index 87b8e3b5f..27d6720ac 100644 --- a/user/src/main/java/org/dicadeveloper/weplantaforest/user/User.java +++ b/user/src/main/java/org/dicadeveloper/weplantaforest/user/User.java @@ -21,6 +21,7 @@ import javax.persistence.Transient; import org.dicadeveloper.weplantaforest.common.support.Language; +import org.dicadeveloper.weplantaforest.common.user.IUser; import org.dicadeveloper.weplantaforest.common.user.Role; import org.dicadeveloper.weplantaforest.team.Team; import org.dicadeveloper.weplantaforest.views.Views; @@ -41,7 +42,7 @@ @Setter @Table(name = "User") @EqualsAndHashCode(exclude = { "team" }) -public class User implements UserDetails { +public class User implements UserDetails, IUser { private static final long serialVersionUID = -4288563962830437191L; @@ -123,6 +124,7 @@ public void removeRole(final Role role) { roles.remove(role); } + @Override @Transient @JsonIgnore public boolean isAdmin() { diff --git a/user/user.gradle b/user/user.gradle index 79159a491..216463686 100644 --- a/user/user.gradle +++ b/user/user.gradle @@ -20,7 +20,7 @@ dependencies{ runtimeOnly group: 'com.github.ben-manes.caffeine', name: 'caffeine', version: '2.8.0' implementation 'org.springframework.boot:spring-boot-starter-cache:' + springBootVersion - implementation 'javax.xml.bind:jaxb-api:2.3.1' + implementation project(':common') implementation('org.springframework.boot:spring-boot-starter-data-jpa:' + springBootVersion) implementation('org.springframework.boot:spring-boot-starter-web:' + springBootVersion) From ea61f1bf64ada6e53af271a9ab5407d70a7107e6 Mon Sep 17 00:00:00 2001 From: Martin Schaaf <703355+mschaaf@users.noreply.github.com> Date: Mon, 12 Jul 2021 16:05:45 +0200 Subject: [PATCH 3/3] weplantaforest #221 - Refactor token handling --- .../weplantaforest/admin/user/User.java | 5 -- .../WebSecurityConfigurerAdapterExt.java | 5 +- .../weplantaforest/cart/CartController.java | 20 ++++-- .../certificate/CertificateController.java | 5 +- .../weplantaforest/code/CodeController.java | 10 ++- .../weplantaforest/gift/GiftController.java | 9 ++- .../weplantaforest/gift/GiftService.java | 2 +- .../payment/PaymentController.java | 7 +- .../planting/PlantPageController.java | 6 +- .../planting/SimplePlantPageController.java | 11 ++- .../planting/plantbag/PlantBagValidator.java | 12 ++-- .../planting/self/SelfPlantController.java | 9 ++- .../self/SelfPlantDataToTreeConverter.java | 2 +- .../offer/ProjectOfferController.java | 5 +- .../projects/offer/ProjectOfferHelper.java | 6 +- .../receipt/ReceiptController.java | 16 +++-- .../support/PlantBagToCartConverter.java | 5 +- .../weplantaforest/team/TeamController.java | 71 +++++++++++-------- .../weplantaforest/user/User.java | 5 -- 19 files changed, 125 insertions(+), 86 deletions(-) diff --git a/admin/src/main/java/org/dicadeveloper/weplantaforest/admin/user/User.java b/admin/src/main/java/org/dicadeveloper/weplantaforest/admin/user/User.java index 7dbd729e1..f889c89a6 100644 --- a/admin/src/main/java/org/dicadeveloper/weplantaforest/admin/user/User.java +++ b/admin/src/main/java/org/dicadeveloper/weplantaforest/admin/user/User.java @@ -154,11 +154,6 @@ public Collection getAuthorities() { return authorities; } - @Override - public String toString() { - return "'" + name + "'(" + mail + ")[" + id + "]"; - } - @Override public String getUsername() { return name; diff --git a/user/src/main/java/org/dicadeveloper/weplantaforest/WebSecurityConfigurerAdapterExt.java b/user/src/main/java/org/dicadeveloper/weplantaforest/WebSecurityConfigurerAdapterExt.java index 9180b963a..f4eefdfbb 100644 --- a/user/src/main/java/org/dicadeveloper/weplantaforest/WebSecurityConfigurerAdapterExt.java +++ b/user/src/main/java/org/dicadeveloper/weplantaforest/WebSecurityConfigurerAdapterExt.java @@ -31,9 +31,6 @@ public class WebSecurityConfigurerAdapterExt extends WebSecurityConfigurerAdapte @Autowired private TokenAuthenticationService tokenAuthenticationService; - @Autowired - private UserDetailsService userDetailsService; - public WebSecurityConfigurerAdapterExt() { super(true); } @@ -57,7 +54,7 @@ protected void configure(HttpSecurity http) throws Exception { // custom Token based authentication based on the header // previously // given to the client - .addFilterBefore(new StatelessAuthenticationFilter(tokenAuthenticationService, userDetailsService), UsernamePasswordAuthenticationFilter.class); + .addFilterBefore(new StatelessAuthenticationFilter(tokenAuthenticationService), UsernamePasswordAuthenticationFilter.class); } diff --git a/user/src/main/java/org/dicadeveloper/weplantaforest/cart/CartController.java b/user/src/main/java/org/dicadeveloper/weplantaforest/cart/CartController.java index b3abf10b4..93994b3b7 100644 --- a/user/src/main/java/org/dicadeveloper/weplantaforest/cart/CartController.java +++ b/user/src/main/java/org/dicadeveloper/weplantaforest/cart/CartController.java @@ -4,7 +4,7 @@ import org.dicadeveloper.weplantaforest.security.TokenAuthenticationService; import org.dicadeveloper.weplantaforest.support.Uris; -import org.dicadeveloper.weplantaforest.user.User; +import org.dicadeveloper.weplantaforest.user.UserRepository; import org.dicadeveloper.weplantaforest.views.Views; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; @@ -18,6 +18,7 @@ import lombok.NonNull; import lombok.RequiredArgsConstructor; +import lombok.val; @RestController @RequiredArgsConstructor(onConstructor = @__(@Autowired)) @@ -28,17 +29,21 @@ public class CartController { @Autowired private TokenAuthenticationService _tokenAuthenticationService; + @Autowired + private UserRepository _userRepository; + /* * get all verified carts by userId */ @RequestMapping(value = Uris.VERIFIFIED_CART_SHORT_VIEW + "{userId}", method = RequestMethod.GET) @JsonView(Views.ShortCart.class) public ResponseEntity> getShortCartsByUser(@RequestHeader(value = "X-AUTH-TOKEN") String userToken) { - User owner = _tokenAuthenticationService.getUserFromToken(userToken); - if (owner == null) { + val user = _tokenAuthenticationService.getUserFromToken(userToken); + if (user == null) { return new ResponseEntity<>(HttpStatus.BAD_REQUEST); } else { - List cartList = _cartRepository.findVerifiedCartsByUserId(owner.getId()); + val userId = _userRepository.findByName(user.getName()).getId(); + val cartList = _cartRepository.findVerifiedCartsByUserId(userId); return new ResponseEntity<>(cartList, HttpStatus.OK); } } @@ -46,9 +51,10 @@ public ResponseEntity> getShortCartsByUser(@RequestHeader(value = "X- @RequestMapping(value = Uris.LAST_CART, method = RequestMethod.GET) @JsonView(Views.LastCartDetails.class) public ResponseEntity getDetailsOfLastCart(@RequestHeader(value = "X-AUTH-TOKEN") String userToken) { - User owner = _tokenAuthenticationService.getUserFromToken(userToken); - if (owner != null) { - Cart cart = _cartRepository.getDetailsOfLastCartByUser(owner.getId()); + val user = _tokenAuthenticationService.getUserFromToken(userToken); + if (user != null) { + val userId = _userRepository.findByName(user.getName()).getId(); + val cart = _cartRepository.getDetailsOfLastCartByUser(userId); return new ResponseEntity<>(cart, HttpStatus.OK); } else { return new ResponseEntity<>(HttpStatus.BAD_REQUEST); diff --git a/user/src/main/java/org/dicadeveloper/weplantaforest/certificate/CertificateController.java b/user/src/main/java/org/dicadeveloper/weplantaforest/certificate/CertificateController.java index 471f3f876..afd495ff7 100644 --- a/user/src/main/java/org/dicadeveloper/weplantaforest/certificate/CertificateController.java +++ b/user/src/main/java/org/dicadeveloper/weplantaforest/certificate/CertificateController.java @@ -92,10 +92,11 @@ public ResponseEntity findCertificateText(@PathVariable("certificat @RequestMapping(value = Uris.CERTIFICATE_CREATE, method = RequestMethod.POST) @Transactional public ResponseEntity createCertificate(@RequestHeader(value = "X-AUTH-TOKEN") String userToken, @RequestBody CertificateRequestData requestData) { - val user = _tokenAuthenticationService.getUserFromToken(userToken); - if (user == null) { + val authUser = _tokenAuthenticationService.getUserFromToken(userToken); + if (authUser == null) { return new ResponseEntity<>(HttpStatus.BAD_REQUEST); } else { + val user = _userRepository.findByName(authUser.getName()); Certificate certificate = new Certificate(); certificate.setCreator(user); certificate.setText(requestData.getText()); diff --git a/user/src/main/java/org/dicadeveloper/weplantaforest/code/CodeController.java b/user/src/main/java/org/dicadeveloper/weplantaforest/code/CodeController.java index 8d21caa40..400b73386 100644 --- a/user/src/main/java/org/dicadeveloper/weplantaforest/code/CodeController.java +++ b/user/src/main/java/org/dicadeveloper/weplantaforest/code/CodeController.java @@ -3,6 +3,7 @@ import org.dicadeveloper.weplantaforest.common.errorhandling.IpatException; import org.dicadeveloper.weplantaforest.security.TokenAuthenticationService; import org.dicadeveloper.weplantaforest.user.User; +import org.dicadeveloper.weplantaforest.user.UserRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -13,6 +14,7 @@ import lombok.NonNull; import lombok.RequiredArgsConstructor; +import lombok.val; @RestController @RequiredArgsConstructor(onConstructor = @__(@Autowired)) @@ -24,10 +26,14 @@ public class CodeController { private @NonNull CodeService _codeService; + @Autowired + private UserRepository _userRepository; + @PostMapping(value = REQUEST_URL + "/redeem") public ResponseEntity redeemCode(@RequestHeader(value = "X-AUTH-TOKEN") String userToken, @RequestParam String codeString) throws IpatException { - User recipient = _tokenAuthenticationService.getUserFromToken(userToken); - if (recipient != null) { + val authUser = _tokenAuthenticationService.getUserFromToken(userToken); + if (authUser != null) { + val recipient = _userRepository.findByName(authUser.getName()); _codeService.redeemCode(recipient, codeString); return new ResponseEntity<>(HttpStatus.OK); } else { diff --git a/user/src/main/java/org/dicadeveloper/weplantaforest/gift/GiftController.java b/user/src/main/java/org/dicadeveloper/weplantaforest/gift/GiftController.java index b9f804653..c721cd7b8 100644 --- a/user/src/main/java/org/dicadeveloper/weplantaforest/gift/GiftController.java +++ b/user/src/main/java/org/dicadeveloper/weplantaforest/gift/GiftController.java @@ -16,7 +16,6 @@ import org.dicadeveloper.weplantaforest.security.TokenAuthenticationService; import org.dicadeveloper.weplantaforest.support.PlantBagToCartConverter; import org.dicadeveloper.weplantaforest.support.Uris; -import org.dicadeveloper.weplantaforest.user.User; import org.dicadeveloper.weplantaforest.user.UserRepository; import org.dicadeveloper.weplantaforest.views.Views; import org.springframework.beans.factory.annotation.Autowired; @@ -88,13 +87,13 @@ public ResponseEntity findGiftsByRecipient(@RequestHeader(value = "X-AUTH-TOK @RequestMapping(value = Uris.GIFT_CREATE, method = RequestMethod.POST) @Transactional public ResponseEntity generateGift(@RequestHeader(value = "X-AUTH-TOKEN") String userToken, @RequestBody PlantBag plantBag) throws IpatException { - User consignor = _tokenAuthenticationService.getUserFromToken(userToken); - if (consignor != null) { + val authUser = _tokenAuthenticationService.getUserFromToken(userToken); + if (authUser != null) { + val consignor = _userRepository.findByName(authUser.getName()); Long[] responseIds = _giftService.generateGift(consignor, plantBag); return new ResponseEntity<>(responseIds, HttpStatus.OK); - } else { - return new ResponseEntity<>(HttpStatus.FORBIDDEN); } + return new ResponseEntity<>(HttpStatus.FORBIDDEN); } @RequestMapping(value = Uris.GIFT_PDF, method = RequestMethod.GET, headers = "Accept=application/pdf") diff --git a/user/src/main/java/org/dicadeveloper/weplantaforest/gift/GiftService.java b/user/src/main/java/org/dicadeveloper/weplantaforest/gift/GiftService.java index 95a321f4c..10d67bb1d 100755 --- a/user/src/main/java/org/dicadeveloper/weplantaforest/gift/GiftService.java +++ b/user/src/main/java/org/dicadeveloper/weplantaforest/gift/GiftService.java @@ -50,7 +50,7 @@ public class GiftService { private final static String RELATIVE_STATIC_IMAGES_PATH = "/static/images/pdf"; @Transactional - public Long[] generateGift(User consignor, PlantBag plantBag) throws IpatException { + public Long[] generateGift(@NonNull User consignor, @NonNull PlantBag plantBag) throws IpatException { Long[] ids = new Long[2]; _plantBagValidator.validatePlantBag(plantBag); Cart cart = plantBagToCartConverter.convertPlantPageDataToCart(plantBag, consignor, CartState.INITIAL); diff --git a/user/src/main/java/org/dicadeveloper/weplantaforest/payment/PaymentController.java b/user/src/main/java/org/dicadeveloper/weplantaforest/payment/PaymentController.java index 489b5c602..93de0ba36 100644 --- a/user/src/main/java/org/dicadeveloper/weplantaforest/payment/PaymentController.java +++ b/user/src/main/java/org/dicadeveloper/weplantaforest/payment/PaymentController.java @@ -3,6 +3,7 @@ import org.dicadeveloper.weplantaforest.common.errorhandling.IpatException; import org.dicadeveloper.weplantaforest.security.TokenAuthenticationService; import org.dicadeveloper.weplantaforest.support.Uris; +import org.dicadeveloper.weplantaforest.user.UserRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -24,9 +25,13 @@ public class PaymentController { private @NonNull TokenAuthenticationService _tokenAuthenticationService; + @Autowired + private UserRepository _userRepository; + @RequestMapping(value = Uris.PAY_PLANTBAG, method = RequestMethod.POST) public ResponseEntity payPlantBag(@RequestHeader(value = "X-AUTH-TOKEN") String userToken, @RequestBody PaymentData paymentData) throws IpatException { - val buyer = _tokenAuthenticationService.getUserFromToken(userToken); + val authUser = _tokenAuthenticationService.getUserFromToken(userToken); + val buyer = _userRepository.findByName(authUser.getName()); _paymentService.payPlantBag(paymentData, buyer); return new ResponseEntity<>(HttpStatus.OK); } diff --git a/user/src/main/java/org/dicadeveloper/weplantaforest/planting/PlantPageController.java b/user/src/main/java/org/dicadeveloper/weplantaforest/planting/PlantPageController.java index 3fb5161d8..851fe5c9a 100644 --- a/user/src/main/java/org/dicadeveloper/weplantaforest/planting/PlantPageController.java +++ b/user/src/main/java/org/dicadeveloper/weplantaforest/planting/PlantPageController.java @@ -35,6 +35,7 @@ import lombok.NonNull; import lombok.RequiredArgsConstructor; +import lombok.val; @RestController @RequiredArgsConstructor(onConstructor = @__(@Autowired)) @@ -71,8 +72,9 @@ public PlantBag getCartProposal(@PathVariable long targetedPrice) { @RequestMapping(value = Uris.COMPLEX_DONATION, method = RequestMethod.POST) @Transactional public ResponseEntity processPlant(@RequestHeader(value = "X-AUTH-TOKEN") String userToken, @RequestBody PlantBag plantBag) throws IpatException { - User buyer = _tokenAuthenticationService.getBuyer(userToken); - if (buyer != null) { + val authUser = _tokenAuthenticationService.getUserFromToken(userToken); + if (authUser != null) { + val buyer = _userRepository.findByName(authUser.getName()); final Cart previousUnpaidCart = _cartRepository.findCartByUserAndOpen(buyer.getId()); if (null != previousUnpaidCart) { if (null != previousUnpaidCart.getCode()) { diff --git a/user/src/main/java/org/dicadeveloper/weplantaforest/planting/SimplePlantPageController.java b/user/src/main/java/org/dicadeveloper/weplantaforest/planting/SimplePlantPageController.java index f8bd2b7e0..a2cd21e0e 100644 --- a/user/src/main/java/org/dicadeveloper/weplantaforest/planting/SimplePlantPageController.java +++ b/user/src/main/java/org/dicadeveloper/weplantaforest/planting/SimplePlantPageController.java @@ -10,7 +10,7 @@ import org.dicadeveloper.weplantaforest.support.PlantBagToCartConverter; import org.dicadeveloper.weplantaforest.support.Uris; import org.dicadeveloper.weplantaforest.trees.TreeRepository; -import org.dicadeveloper.weplantaforest.user.User; +import org.dicadeveloper.weplantaforest.user.UserRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -25,6 +25,7 @@ import lombok.NonNull; import lombok.RequiredArgsConstructor; +import lombok.val; @RestController @RequiredArgsConstructor(onConstructor = @__(@Autowired)) @@ -42,6 +43,9 @@ public class SimplePlantPageController { private @NonNull TokenAuthenticationService _tokenAuthenticationService; + @Autowired + private UserRepository _userRepository; + @RequestMapping(value = Uris.SIMPLE_PROPOSAL_FOR_TREE + "{amountOfTrees}", method = RequestMethod.GET) @Transactional public SimplePlantBag getCartProposalForAmountOfTrees(@PathVariable long amountOfTrees) throws IpatException { @@ -56,9 +60,10 @@ public SimplePlantBag getCartProposalForAmountOfTrees(@RequestParam String proje @RequestMapping(value = Uris.SIMPLE_DONATION, method = RequestMethod.POST) public ResponseEntity processPlant(@RequestHeader(value = "X-AUTH-TOKEN") String userToken, @RequestBody SimplePlantBag plantPageData) { - User buyer = _tokenAuthenticationService.getUserFromToken(userToken); - if (buyer != null) { + val authUser = _tokenAuthenticationService.getUserFromToken(userToken); + if (authUser != null) { if (_simplePlantPageDataValidator.isPlantPageDataValid(plantPageData)) { + val buyer = _userRepository.findByName(authUser.getName()); Cart cart = plantPageToCartConverter.convertSimplePlantPageDataToCart(plantPageData, buyer); _cartRepository.save(cart); return new ResponseEntity<>(HttpStatus.OK); diff --git a/user/src/main/java/org/dicadeveloper/weplantaforest/planting/plantbag/PlantBagValidator.java b/user/src/main/java/org/dicadeveloper/weplantaforest/planting/plantbag/PlantBagValidator.java index 8ed90ab5b..6a1c6d5a1 100644 --- a/user/src/main/java/org/dicadeveloper/weplantaforest/planting/plantbag/PlantBagValidator.java +++ b/user/src/main/java/org/dicadeveloper/weplantaforest/planting/plantbag/PlantBagValidator.java @@ -14,6 +14,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import lombok.NonNull; + @Component public class PlantBagValidator extends AbstractPlantBagValidator { @@ -22,7 +24,7 @@ private PlantBagValidator(TreeRepository treeRepository, ProjectArticleRepositor super(treeRepository, projectArticleRepository, projectRepository); } - public void validatePlantBag(PlantBag plantBag) throws IpatException { + public void validatePlantBag(@NonNull PlantBag plantBag) throws IpatException { Set projectNames = plantBag.getProjects().keySet(); checkProjects(plantBag, projectNames); if (errorInfos.size() > 0) { @@ -32,27 +34,27 @@ public void validatePlantBag(PlantBag plantBag) throws IpatException { } } - private void checkProjects(PlantBag plantBag, Set projectNames) { + private void checkProjects(@NonNull PlantBag plantBag, @NonNull Set projectNames) { for (String projectName : projectNames) { checkProject(plantBag, projectName); } } - private void checkProject(PlantBag plantBag, String projectName) { + private void checkProject(@NonNull PlantBag plantBag, @NonNull String projectName) { Project project = projectExistsTemp(projectName); if (project != null && isProjectActiveTemp(project)) { checkArticles(plantBag, projectName); } } - private void checkArticles(PlantBag plantBag, String projectName) { + private void checkArticles(@NonNull PlantBag plantBag, @NonNull String projectName) { Set articleNames = plantBag.getProjects().get(projectName).getPlantItems().keySet(); for (String articleName : articleNames) { checkArticle(plantBag, projectName, articleName); } } - private void checkArticle(PlantBag plantBag, String projectName, String articleName) { + private void checkArticle(@NonNull PlantBag plantBag, @NonNull String projectName, @NonNull String articleName) { ProjectArticle article = articleExistsTemp(projectName, articleName); if (article != null) { Long wantedToPlant = (long) plantBag.getProjects().get(projectName).getPlantItems().get(articleName).getAmount(); diff --git a/user/src/main/java/org/dicadeveloper/weplantaforest/planting/self/SelfPlantController.java b/user/src/main/java/org/dicadeveloper/weplantaforest/planting/self/SelfPlantController.java index 3a8c2a79d..a541f050d 100644 --- a/user/src/main/java/org/dicadeveloper/weplantaforest/planting/self/SelfPlantController.java +++ b/user/src/main/java/org/dicadeveloper/weplantaforest/planting/self/SelfPlantController.java @@ -15,7 +15,7 @@ import org.dicadeveloper.weplantaforest.trees.Tree; import org.dicadeveloper.weplantaforest.trees.TreeRepository; import org.dicadeveloper.weplantaforest.treetypes.TreeTypeRepository; -import org.dicadeveloper.weplantaforest.user.User; +import org.dicadeveloper.weplantaforest.user.UserRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -49,10 +49,15 @@ public class SelfPlantController { private @NonNull ImageHelper _imageHelper; + @Autowired + private UserRepository _userRepository; + @RequestMapping(value = Uris.PLANT_SELF, method = RequestMethod.POST) public ResponseEntity plantTreesByMyself(@RequestHeader(value = "X-AUTH-TOKEN") String userToken, @Valid @RequestBody SelfPlantData selfPlantedTree, BindingResult bindingResult) { if (!bindingResult.hasErrors()) { - User owner = _tokenAuthenticationService.getUserFromToken(userToken); + val authUser = _tokenAuthenticationService.getUserFromToken(userToken); + val owner = _userRepository.findByName(authUser.getName()); + Tree tree = _selfPlantDataToTreeConverter.convertSelfPlantDataToTree(selfPlantedTree, owner); _treeRepository.save(tree); return new ResponseEntity(tree.getId(), HttpStatus.OK); diff --git a/user/src/main/java/org/dicadeveloper/weplantaforest/planting/self/SelfPlantDataToTreeConverter.java b/user/src/main/java/org/dicadeveloper/weplantaforest/planting/self/SelfPlantDataToTreeConverter.java index 87ed3865c..312737957 100644 --- a/user/src/main/java/org/dicadeveloper/weplantaforest/planting/self/SelfPlantDataToTreeConverter.java +++ b/user/src/main/java/org/dicadeveloper/weplantaforest/planting/self/SelfPlantDataToTreeConverter.java @@ -22,7 +22,7 @@ private SelfPlantDataToTreeConverter(UserRepository userRepository, TreeTypeRepo _treeTypeRepository = treeTypeRepository; } - protected Tree convertSelfPlantDataToTree(SelfPlantData selfPlantData, User owner) { + protected Tree convertSelfPlantDataToTree(@NonNull SelfPlantData selfPlantData, @NonNull User owner) { Tree tree = new Tree(); long submittedOn = System.currentTimeMillis(); diff --git a/user/src/main/java/org/dicadeveloper/weplantaforest/projects/offer/ProjectOfferController.java b/user/src/main/java/org/dicadeveloper/weplantaforest/projects/offer/ProjectOfferController.java index c19ac4075..ce3949aa6 100644 --- a/user/src/main/java/org/dicadeveloper/weplantaforest/projects/offer/ProjectOfferController.java +++ b/user/src/main/java/org/dicadeveloper/weplantaforest/projects/offer/ProjectOfferController.java @@ -4,7 +4,6 @@ import org.dicadeveloper.weplantaforest.common.mail.MailHelper; import org.dicadeveloper.weplantaforest.security.TokenAuthenticationService; -import org.dicadeveloper.weplantaforest.user.User; import org.dicadeveloper.weplantaforest.user.UserRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; @@ -18,6 +17,7 @@ import lombok.NonNull; import lombok.RequiredArgsConstructor; +import lombok.val; @RestController @RequiredArgsConstructor(onConstructor = @__(@Autowired)) @@ -35,10 +35,11 @@ public ResponseEntity offerProject(@RequestHeader(value = "X-AUTH-TOKEN") Str final String subject = ProjectOfferHelper.createSubject(projectOffer.getName(), projectOffer.getMail()); String text; - User user = _tokenAuthenticationService.getUserFromToken(userToken); + val user = _tokenAuthenticationService.getUserFromToken(userToken); text = ProjectOfferHelper.createMailText(projectOffer, user); new Thread(new Runnable() { + @Override public void run() { _mailHelper.sendAMessage(subject, text); } diff --git a/user/src/main/java/org/dicadeveloper/weplantaforest/projects/offer/ProjectOfferHelper.java b/user/src/main/java/org/dicadeveloper/weplantaforest/projects/offer/ProjectOfferHelper.java index 8d4ccb0be..83533856f 100644 --- a/user/src/main/java/org/dicadeveloper/weplantaforest/projects/offer/ProjectOfferHelper.java +++ b/user/src/main/java/org/dicadeveloper/weplantaforest/projects/offer/ProjectOfferHelper.java @@ -1,7 +1,7 @@ package org.dicadeveloper.weplantaforest.projects.offer; import org.dicadeveloper.weplantaforest.common.support.StringHelper; -import org.dicadeveloper.weplantaforest.user.User; +import org.dicadeveloper.weplantaforest.common.user.IUser; public class ProjectOfferHelper { @@ -9,11 +9,11 @@ protected static String createSubject(String name, String mail) { return "[Projekt Angebot] " + name + " " + mail; } - protected static String createMailText(ProjectOfferData projectOffer, User user) { + protected static String createMailText(final ProjectOfferData projectOffer, final IUser user) { final StringBuilder text = new StringBuilder(); if (user != null) { - text.append("User: " + user + "\n"); + text.append("User: " + user.getName() + "\n"); } text.append("Name: " + projectOffer.getName() + "\n"); diff --git a/user/src/main/java/org/dicadeveloper/weplantaforest/receipt/ReceiptController.java b/user/src/main/java/org/dicadeveloper/weplantaforest/receipt/ReceiptController.java index 194ad08c9..54b819953 100644 --- a/user/src/main/java/org/dicadeveloper/weplantaforest/receipt/ReceiptController.java +++ b/user/src/main/java/org/dicadeveloper/weplantaforest/receipt/ReceiptController.java @@ -12,7 +12,6 @@ import org.dicadeveloper.weplantaforest.cart.CartRepository; import org.dicadeveloper.weplantaforest.security.TokenAuthenticationService; import org.dicadeveloper.weplantaforest.support.Uris; -import org.dicadeveloper.weplantaforest.user.User; import org.dicadeveloper.weplantaforest.user.UserRepository; import org.dicadeveloper.weplantaforest.views.Views; import org.springframework.beans.factory.annotation.Autowired; @@ -30,6 +29,7 @@ import lombok.NonNull; import lombok.RequiredArgsConstructor; +import lombok.val; @RestController @RequiredArgsConstructor(onConstructor = @__(@Autowired)) @@ -54,10 +54,11 @@ public class ReceiptController { @RequestMapping(value = Uris.RECEIPTS, method = RequestMethod.GET) @JsonView(Views.ReceiptOverview.class) public ResponseEntity getReceiptsByOwnerId(@RequestHeader(value = "X-AUTH-TOKEN") String userToken) { - User user = _tokenAuthenticationService.getUserFromToken(userToken); - if (user == null) { + val authUser = _tokenAuthenticationService.getUserFromToken(userToken); + if (authUser == null) { return new ResponseEntity<>(HttpStatus.FORBIDDEN); } else { + val user = _userRepository.findByName(authUser.getName()); List receipts = _receiptRepository.findByOwnerId(user.getId()); return new ResponseEntity<>(receipts, HttpStatus.OK); } @@ -65,10 +66,15 @@ public ResponseEntity getReceiptsByOwnerId(@RequestHeader(value = "X-AUTH-TOK @RequestMapping(value = Uris.RECEIPT_PDF, method = RequestMethod.GET, headers = "Accept=application/pdf") public ResponseEntity createReceiptPdf(HttpServletResponse response, @RequestParam Long receiptId, @RequestHeader(value = "X-AUTH-TOKEN") String userToken) { - User user = _tokenAuthenticationService.getUserFromToken(userToken); - if (user == null || !_receiptRepository.existsByReceiptIdAndOwnerId(receiptId, user.getId())) { + val authUser = _tokenAuthenticationService.getUserFromToken(userToken); + if (authUser == null) { return new ResponseEntity<>(HttpStatus.FORBIDDEN); } else { + val user = _userRepository.findByName(authUser.getName()); + if (!_receiptRepository.existsByReceiptIdAndOwnerId(receiptId, user.getId())) { + return new ResponseEntity<>(HttpStatus.FORBIDDEN); + } + Receipt receipt = _receiptRepository.findById(receiptId).orElse(null); PdfReceiptView pdf = new PdfReceiptView(); diff --git a/user/src/main/java/org/dicadeveloper/weplantaforest/support/PlantBagToCartConverter.java b/user/src/main/java/org/dicadeveloper/weplantaforest/support/PlantBagToCartConverter.java index c21b962a9..298e9746c 100644 --- a/user/src/main/java/org/dicadeveloper/weplantaforest/support/PlantBagToCartConverter.java +++ b/user/src/main/java/org/dicadeveloper/weplantaforest/support/PlantBagToCartConverter.java @@ -32,7 +32,7 @@ public PlantBagToCartConverter(ProjectArticleRepository projectArticleRepository _userRepository = userRepository; } - public Cart convertPlantPageDataToCart(PlantBag plantPageData, User buyer, CartState cartState) { + public Cart convertPlantPageDataToCart(@NonNull PlantBag plantPageData, User buyer, CartState cartState) { Cart cart = new Cart(); cart.setTimeStamp(System.currentTimeMillis()); @@ -58,8 +58,7 @@ public Cart convertPlantPageDataToCart(PlantBag plantPageData, User buyer, CartS return cart; } - public Cart convertSimplePlantPageDataToCart(SimplePlantBag simplePlantPageData, User buyer) { - + public Cart convertSimplePlantPageDataToCart(@NonNull SimplePlantBag simplePlantPageData, @NonNull User buyer) { Cart cart = new Cart(); cart.setTimeStamp(System.currentTimeMillis()); cart.setBuyer(buyer); diff --git a/user/src/main/java/org/dicadeveloper/weplantaforest/team/TeamController.java b/user/src/main/java/org/dicadeveloper/weplantaforest/team/TeamController.java index 032336828..863bfeaee 100755 --- a/user/src/main/java/org/dicadeveloper/weplantaforest/team/TeamController.java +++ b/user/src/main/java/org/dicadeveloper/weplantaforest/team/TeamController.java @@ -37,6 +37,7 @@ import lombok.NonNull; import lombok.RequiredArgsConstructor; +import lombok.val; import lombok.extern.slf4j.Slf4j; @RestController @@ -58,6 +59,9 @@ public class TeamController { private @NonNull TokenAuthenticationService tokenAuthenticationService; + @Autowired + private UserRepository _userRepository; + @RequestMapping(value = Uris.TEAM_IMAGE + "{imageName:.+}/{width}/{height}", method = RequestMethod.GET, headers = "Accept=image/jpeg, image/jpg, image/png, image/gif") public ResponseEntity getImage(HttpServletResponse response, @PathVariable String imageName, @PathVariable int width, @PathVariable int height) { File directory = new File(FileSystemInjector.getTeamFolder()); @@ -82,13 +86,15 @@ public ResponseEntity getImage(HttpServletResponse response, @PathVariable St @RequestMapping(value = Uris.TEAM_IMAGE_UPLOAD, method = RequestMethod.POST) public ResponseEntity uploadTeamImage(@RequestHeader(value = "X-AUTH-TOKEN") String userToken, @RequestParam Long teamId, @RequestParam("file") MultipartFile file) throws IpatException { - User user = tokenAuthenticationService.getUserFromToken(userToken); - if (null != user && teamService.isTeamAdmin(user.getId(), teamId)) { - teamService.uploadTeamImage(teamId, file); - return new ResponseEntity<>(HttpStatus.OK); - } else { - return new ResponseEntity<>(HttpStatus.FORBIDDEN); + val authUser = tokenAuthenticationService.getUserFromToken(userToken); + if (null != authUser) { + val user = _userRepository.findByName(authUser.getName()); + if (teamService.isTeamAdmin(user.getId(), teamId)) { + teamService.uploadTeamImage(teamId, file); + return new ResponseEntity<>(HttpStatus.OK); + } } + return new ResponseEntity<>(HttpStatus.FORBIDDEN); } @RequestMapping(value = Uris.TEAM_DETAILS, method = RequestMethod.GET) @@ -115,13 +121,15 @@ public ResponseEntity getTeamDetails(@RequestParam String teamName) { @RequestMapping(value = Uris.EDIT_TEAM_DETAILS, method = RequestMethod.POST) public ResponseEntity editTeamDetails(@RequestHeader(value = "X-AUTH-TOKEN") String userToken, @RequestParam Long teamId, @RequestParam String toEdit, @RequestParam String newEntry) throws IpatException { - User user = tokenAuthenticationService.getUserFromToken(userToken); - if (null != user && teamService.isTeamAdmin(user.getId(), teamId)) { - teamService.editTeam(teamId, toEdit, newEntry); - return new ResponseEntity<>(HttpStatus.OK); - } else { - return new ResponseEntity<>(HttpStatus.FORBIDDEN); + val authUser = tokenAuthenticationService.getUserFromToken(userToken); + if (null != authUser) { + val user = _userRepository.findByName(authUser.getName()); + if (teamService.isTeamAdmin(user.getId(), teamId)) { + teamService.editTeam(teamId, toEdit, newEntry); + return new ResponseEntity<>(HttpStatus.OK); + } } + return new ResponseEntity<>(HttpStatus.FORBIDDEN); } @RequestMapping(value = Uris.TEAM_MEMBER, method = RequestMethod.GET) @@ -147,8 +155,9 @@ private long calcTeamRank(String teamName, long treeCountOfTeam) { @RequestMapping(value = Uris.TEAM_CREATE, method = RequestMethod.POST) public ResponseEntity createTeam(@RequestHeader(value = "X-AUTH-TOKEN") String userToken, @Valid @RequestBody Team team) throws IpatException { - User user = tokenAuthenticationService.getUserFromToken(userToken); - if (user != null) { + val authUser = tokenAuthenticationService.getUserFromToken(userToken); + if (authUser != null) { + val user = _userRepository.findByName(authUser.getName()); teamService.createTeam(team, user.getId()); return new ResponseEntity<>(team.getName(), HttpStatus.OK); } else { @@ -158,8 +167,9 @@ public ResponseEntity createTeam(@RequestHeader(value = "X-AUTH-TOKEN") Strin @RequestMapping(value = Uris.TEAM_JOIN, method = RequestMethod.POST) public ResponseEntity joinTeam(@RequestHeader(value = "X-AUTH-TOKEN") String userToken, @RequestParam Long teamId) throws IpatException { - User user = tokenAuthenticationService.getUserFromToken(userToken); - if (user != null) { + val authUser = tokenAuthenticationService.getUserFromToken(userToken); + if (authUser != null) { + val user = _userRepository.findByName(authUser.getName()); teamService.joinTeam(user.getId(), teamId); return new ResponseEntity<>(HttpStatus.OK); } else { @@ -169,8 +179,9 @@ public ResponseEntity joinTeam(@RequestHeader(value = "X-AUTH-TOKEN") String @RequestMapping(value = Uris.TEAM_LEAVE, method = RequestMethod.POST) public ResponseEntity leaveTeam(@RequestHeader(value = "X-AUTH-TOKEN") String userToken) throws IpatException { - User user = tokenAuthenticationService.getUserFromToken(userToken); - if (user != null) { + val authUser = tokenAuthenticationService.getUserFromToken(userToken); + if (authUser != null) { + val user = _userRepository.findByName(authUser.getName()); teamService.leaveTeam(user.getId()); return new ResponseEntity<>(HttpStatus.OK); } else { @@ -180,19 +191,22 @@ public ResponseEntity leaveTeam(@RequestHeader(value = "X-AUTH-TOKEN") String @RequestMapping(value = Uris.TEAM_DELETE, method = RequestMethod.DELETE) public ResponseEntity deleteTeam(@RequestHeader(value = "X-AUTH-TOKEN") String userToken, @RequestParam Long teamId) throws IpatException { - User user = tokenAuthenticationService.getUserFromToken(userToken); - if (null != user && teamService.isTeamAdmin(user.getId(), teamId)) { - teamService.deleteTeam(user, teamId); - return new ResponseEntity<>(HttpStatus.OK); - } else { - return new ResponseEntity<>(HttpStatus.FORBIDDEN); + val authUser = tokenAuthenticationService.getUserFromToken(userToken); + if (null != authUser) { + val user = _userRepository.findByName(authUser.getName()); + if (teamService.isTeamAdmin(user.getId(), teamId)) { + teamService.deleteTeam(user, teamId); + return new ResponseEntity<>(HttpStatus.OK); + } } + return new ResponseEntity<>(HttpStatus.FORBIDDEN); } @RequestMapping(value = Uris.TEAM_IS_ADMIN, method = RequestMethod.GET) public ResponseEntity isAdmin(@RequestHeader(value = "X-AUTH-TOKEN") String userToken, @RequestParam Long teamId) throws IpatException { - User user = tokenAuthenticationService.getUserFromToken(userToken); - if (user != null) { + val authUser = tokenAuthenticationService.getUserFromToken(userToken); + if (authUser != null) { + val user = _userRepository.findByName(authUser.getName()); boolean isAdmin = teamService.isTeamAdmin(user.getId(), teamId); return new ResponseEntity<>(isAdmin, HttpStatus.OK); } else { @@ -202,8 +216,9 @@ public ResponseEntity isAdmin(@RequestHeader(value = "X-AUTH-TOKEN") String u @RequestMapping(value = Uris.TEAM_IS_MEMBER, method = RequestMethod.GET) public ResponseEntity isMember(@RequestHeader(value = "X-AUTH-TOKEN") String userToken, @RequestParam Long teamId) throws IpatException { - User user = tokenAuthenticationService.getUserFromToken(userToken); - if (user != null) { + val authUser = tokenAuthenticationService.getUserFromToken(userToken); + if (authUser != null) { + val user = _userRepository.findByName(authUser.getName()); boolean isMember = teamService.isTeamMember(user.getId(), teamId); return new ResponseEntity<>(isMember, HttpStatus.OK); } else { diff --git a/user/src/main/java/org/dicadeveloper/weplantaforest/user/User.java b/user/src/main/java/org/dicadeveloper/weplantaforest/user/User.java index 27d6720ac..e71dce9de 100644 --- a/user/src/main/java/org/dicadeveloper/weplantaforest/user/User.java +++ b/user/src/main/java/org/dicadeveloper/weplantaforest/user/User.java @@ -131,11 +131,6 @@ public boolean isAdmin() { return roles.contains(Role.ADMIN); } - @Override - public String toString() { - return "'" + name + "'(" + mail + ")[" + id + "]"; - } - @Override @JsonIgnore public Collection getAuthorities() {