From eaf03ea28d8b7f613b9d144085cdac63a4526bfd Mon Sep 17 00:00:00 2001 From: Paulo Gustavo Veiga Date: Sun, 11 Feb 2024 12:21:38 -0800 Subject: [PATCH] Clean up. --- .../config/rest/InterceptorsConfig.java | 39 --------- .../config/rest/RestAppConfig.java | 9 +- .../com/wisemapping/filter/CorsFilter.java | 79 ----------------- .../filter/JwtAuthenticationFilter.java | 12 +-- .../filter/RequestPropertiesInterceptor.java | 83 ------------------ .../main/java/com/wisemapping/model/User.java | 2 +- .../wisemapping/rest/JwtAuthController.java | 60 +++++-------- .../wisemapping/rest/OAuth2Controller.java | 84 +++++++++---------- .../wisemapping/security/JwtTokenUtil.java | 20 +++++ .../com/wisemapping/service/UserService.java | 2 +- .../wisemapping/service/UserServiceImpl.java | 7 +- .../service/google/GoogleService.java | 17 ++-- .../webmvc/MvcLoginController.java | 46 ---------- wise-api/src/main/resources/application.yml | 27 +++--- 14 files changed, 119 insertions(+), 368 deletions(-) delete mode 100644 wise-api/src/main/java/com/wisemapping/config/rest/InterceptorsConfig.java delete mode 100644 wise-api/src/main/java/com/wisemapping/filter/CorsFilter.java delete mode 100644 wise-api/src/main/java/com/wisemapping/filter/RequestPropertiesInterceptor.java delete mode 100644 wise-api/src/main/java/com/wisemapping/webmvc/MvcLoginController.java diff --git a/wise-api/src/main/java/com/wisemapping/config/rest/InterceptorsConfig.java b/wise-api/src/main/java/com/wisemapping/config/rest/InterceptorsConfig.java deleted file mode 100644 index e521b7ea..00000000 --- a/wise-api/src/main/java/com/wisemapping/config/rest/InterceptorsConfig.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright [2022] [wisemapping] - * - * Licensed under WiseMapping Public License, Version 1.0 (the "License"). - * It is basically the Apache License, Version 2.0 (the "License") plus the - * "powered by wisemapping" text requirement on every single page; - * you may not use this file except in compliance with the License. - * You may obtain a copy of the license at - * - * http://www.wisemapping.org/license - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.wisemapping.config.rest; - -import com.wisemapping.filter.RequestPropertiesInterceptor; -import org.jetbrains.annotations.NotNull; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.config.annotation.InterceptorRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; - -@Configuration -@ComponentScan(basePackageClasses = RequestPropertiesInterceptor.class) -public class InterceptorsConfig implements WebMvcConfigurer { - @Autowired - private RequestPropertiesInterceptor requestPropertiesInterceptor; - - @Override - public void addInterceptors(@NotNull final InterceptorRegistry registry) { - registry.addInterceptor(requestPropertiesInterceptor); - } - -} \ No newline at end of file diff --git a/wise-api/src/main/java/com/wisemapping/config/rest/RestAppConfig.java b/wise-api/src/main/java/com/wisemapping/config/rest/RestAppConfig.java index ada33915..a55e0142 100644 --- a/wise-api/src/main/java/com/wisemapping/config/rest/RestAppConfig.java +++ b/wise-api/src/main/java/com/wisemapping/config/rest/RestAppConfig.java @@ -8,7 +8,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Import; 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.configurers.AbstractHttpConfigurer; @@ -21,8 +20,7 @@ import org.springframework.web.servlet.handler.HandlerMappingIntrospector; import static org.springframework.security.config.Customizer.withDefaults; -@SpringBootApplication(scanBasePackageClasses = MindmapController.class) -@Import({InterceptorsConfig.class}) +@SpringBootApplication(scanBasePackageClasses = {MindmapController.class, JwtAuthenticationFilter.class}) @EnableWebSecurity public class RestAppConfig { @@ -43,12 +41,13 @@ public class RestAppConfig { .securityMatcher("/**") .addFilterAfter(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) .authorizeHttpRequests(auth -> auth + .requestMatchers(mvc.pattern("/error")).permitAll() .requestMatchers(mvc.pattern("/api/restful/authenticate")).permitAll() .requestMatchers(mvc.pattern("/api/restful/users/")).permitAll() .requestMatchers(mvc.pattern("/api/restful/maps/*/document/xml-pub")).permitAll() .requestMatchers(mvc.pattern("/api/restful/users/resetPassword")).permitAll() - .requestMatchers(mvc.pattern("/api/restful/oauth2/googlecallback")).permitAll() - .requestMatchers(mvc.pattern("/api/restful/oauth2/confirmaccountsync")).permitAll() + .requestMatchers(mvc.pattern("/api/oauth2/googlecallback")).permitAll() + .requestMatchers(mvc.pattern("/api/oauth2/confirmaccountsync")).permitAll() .requestMatchers(mvc.pattern("/api/restful/admin/**")).hasAnyRole("ADMIN") .requestMatchers(mvc.pattern("/**")).hasAnyRole("USER", "ADMIN") .anyRequest().authenticated() diff --git a/wise-api/src/main/java/com/wisemapping/filter/CorsFilter.java b/wise-api/src/main/java/com/wisemapping/filter/CorsFilter.java deleted file mode 100644 index fd0d53b9..00000000 --- a/wise-api/src/main/java/com/wisemapping/filter/CorsFilter.java +++ /dev/null @@ -1,79 +0,0 @@ -/* -* Copyright [2022] [wisemapping] -* -* Licensed under WiseMapping Public License, Version 1.0 (the "License"). -* It is basically the Apache License, Version 2.0 (the "License") plus the -* "powered by wisemapping" text requirement on every single page; -* you may not use this file except in compliance with the License. -* You may obtain a copy of the license at -* -* http://www.wisemapping.org/license -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package com.wisemapping.filter; - -import java.io.IOException; - -import jakarta.servlet.Filter; -import jakarta.servlet.FilterChain; -import jakarta.servlet.FilterConfig; -import jakarta.servlet.ServletException; -import jakarta.servlet.ServletRequest; -import jakarta.servlet.ServletResponse; -import jakarta.servlet.http.HttpServletResponse; - -/** - * - * If your wisemapping customization throws cross domain errores in browser, you can configure this filter in webdefault.xml - * By default it will accept all domains, but you can restrict to the domain you need - * - * - * cross-origin - * com.wisemapping.filter.CorsFilter - * - * allowedOrigins - * * - * - * - * allowedMethods - * GET,POST,HEAD - * - * - * allowedHeaders - * X-Requested-With,Content-Type,Accept,Origin - * - * - * - * cross-origin - * /* - * - * - */ -public class CorsFilter implements Filter { - - @Override - public void init(FilterConfig filterConfig) throws ServletException { - } - - @Override - public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) - throws IOException, ServletException { - if (servletResponse != null) { - // Authorize (allow) all domains to consume the content - ((HttpServletResponse) servletResponse).addHeader("Access-Control-Allow-Origin", "*"); - ((HttpServletResponse) servletResponse).addHeader("Access-Control-Allow-Methods","GET, OPTIONS, HEAD, PUT, POST"); - } - - chain.doFilter(servletRequest, servletResponse); - } - - @Override - public void destroy() { - } -} diff --git a/wise-api/src/main/java/com/wisemapping/filter/JwtAuthenticationFilter.java b/wise-api/src/main/java/com/wisemapping/filter/JwtAuthenticationFilter.java index 9b376273..927cb650 100644 --- a/wise-api/src/main/java/com/wisemapping/filter/JwtAuthenticationFilter.java +++ b/wise-api/src/main/java/com/wisemapping/filter/JwtAuthenticationFilter.java @@ -11,7 +11,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.dao.DataAccessException; +import org.springframework.http.HttpHeaders; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UsernameNotFoundException; @@ -22,10 +22,10 @@ import org.springframework.web.filter.OncePerRequestFilter; import java.io.IOException; import java.util.Optional; +import static com.wisemapping.security.JwtTokenUtil.BEARER_TOKEN_PREFIX; + @Component public class JwtAuthenticationFilter extends OncePerRequestFilter { - private static final String BEARER_TOKEN_PREFIX = "Bearer "; - private static final String AUTHORIZATION_HEADER = "Authorization"; @Autowired private UserDetailsService userDetailsService; @@ -35,7 +35,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { final private static Logger logger = LogManager.getLogger(); @Override - protected void doFilterInternal(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull FilterChain filterChain) + protected void doFilterInternal(@NotNull final HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull FilterChain filterChain) throws ServletException, IOException { final Optional token = getJwtTokenFromRequest(request); @@ -62,7 +62,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { private Optional extractEmailFromToken(final @NotNull String token) { Optional result = Optional.empty(); try { - result = Optional.of(jwtTokenUtil.extractFromJwtToken(token)); + result = Optional.ofNullable(jwtTokenUtil.extractFromJwtToken(token)); } catch (Exception e) { // Handle token extraction/validation errors logger.debug("Error extracting email from token: " + e.getMessage()); @@ -74,7 +74,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { private static Optional getJwtTokenFromRequest(@NotNull HttpServletRequest request) { Optional result = Optional.empty(); - final String authorizationHeader = request.getHeader(AUTHORIZATION_HEADER); + final String authorizationHeader = request.getHeader(HttpHeaders.AUTHORIZATION); if (authorizationHeader != null) { if (authorizationHeader.startsWith(BEARER_TOKEN_PREFIX)) { logger.trace("JWT Bearer token found."); diff --git a/wise-api/src/main/java/com/wisemapping/filter/RequestPropertiesInterceptor.java b/wise-api/src/main/java/com/wisemapping/filter/RequestPropertiesInterceptor.java deleted file mode 100644 index 9c222c77..00000000 --- a/wise-api/src/main/java/com/wisemapping/filter/RequestPropertiesInterceptor.java +++ /dev/null @@ -1,83 +0,0 @@ -/* -* Copyright [2022] [wisemapping] -* -* Licensed under WiseMapping Public License, Version 1.0 (the "License"). -* It is basically the Apache License, Version 2.0 (the "License") plus the -* "powered by wisemapping" text requirement on every single page; -* you may not use this file except in compliance with the License. -* You may obtain a copy of the license at -* -* http://www.wisemapping.org/license -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package com.wisemapping.filter; - -import org.jetbrains.annotations.NotNull; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; -import org.springframework.web.servlet.HandlerInterceptor; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; - - -@Component -public class RequestPropertiesInterceptor implements HandlerInterceptor { - @Value("${google.analytics.enabled}") - private Boolean analyticsEnabled; - - @Value("${google.analytics.account}") - private String analyticsAccount; - - @Value("${google.recaptcha2.enabled}") - private Boolean recaptcha2Enabled; - - @Value("${site.static.js.url}") - private String siteStaticUrl; - - @Value("${google.recaptcha2.siteKey}") - private String recaptcha2SiteKey; - - @Value("${google.ads.enabled}") - private Boolean adsEnabled; - - @Value("${site.homepage}") - private String siteHomepage; - - @Value("${site.baseurl:}") - private String siteUrl; - - @Value("${security.oauth2.google.url}") - private String googleOauth2Url; - - @Override - public boolean preHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, Object object) throws Exception { - - request.setAttribute("google.analytics.enabled", analyticsEnabled); - request.setAttribute("google.analytics.account", analyticsAccount); - request.setAttribute("google.ads.enabled", adsEnabled); - - request.setAttribute("google.recaptcha2.enabled", recaptcha2Enabled); - request.setAttribute("google.recaptcha2.siteKey", recaptcha2SiteKey); - - request.setAttribute("security.oauth2.google.url", googleOauth2Url); - - request.setAttribute("site.homepage", siteHomepage); - request.setAttribute("site.static.js.url", siteStaticUrl); - - request.setAttribute("security.type", "db"); - - // If the property could not be resolved, try to infer one from the request... - if (siteUrl.isBlank()) { - siteUrl = request.getRequestURL().toString().replace(request.getRequestURI(), request.getContextPath()); - } - request.setAttribute("site.baseurl", siteUrl); - return true; - } -} diff --git a/wise-api/src/main/java/com/wisemapping/model/User.java b/wise-api/src/main/java/com/wisemapping/model/User.java index 39f6e8a1..2d2b6a21 100644 --- a/wise-api/src/main/java/com/wisemapping/model/User.java +++ b/wise-api/src/main/java/com/wisemapping/model/User.java @@ -164,7 +164,7 @@ public class User } public Boolean getGoogleSync() { - return googleSync; + return googleSync!=null && googleSync; } public void setGoogleSync(Boolean googleSync) { diff --git a/wise-api/src/main/java/com/wisemapping/rest/JwtAuthController.java b/wise-api/src/main/java/com/wisemapping/rest/JwtAuthController.java index 879ec8a1..01202552 100644 --- a/wise-api/src/main/java/com/wisemapping/rest/JwtAuthController.java +++ b/wise-api/src/main/java/com/wisemapping/rest/JwtAuthController.java @@ -18,64 +18,44 @@ package com.wisemapping.rest; +import com.wisemapping.exceptions.WiseMappingException; import com.wisemapping.rest.model.RestJwtUser; import com.wisemapping.security.JwtTokenUtil; -import com.wisemapping.security.UserDetailsService; import jakarta.servlet.http.HttpServletResponse; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpHeaders; import org.springframework.http.ResponseEntity; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.DisabledException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.web.bind.annotation.CrossOrigin; -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.web.bind.annotation.*; @RestController @CrossOrigin @RequestMapping("/api/restful") public class JwtAuthController { - @Autowired - private AuthenticationManager authenticationManager; + @Autowired + private AuthenticationManager authenticationManager; - @Autowired - private UserDetailsService userDetailsService; + @Autowired + private JwtTokenUtil jwtTokenUtil; - @Autowired - private JwtTokenUtil jwtTokenUtil; + @RequestMapping(value = "/authenticate", method = RequestMethod.POST) + public ResponseEntity createAuthenticationToken(@RequestBody RestJwtUser user, @NotNull HttpServletResponse response) throws WiseMappingException { + // Is a valid user ? + authenticate(user.getEmail(), user.getPassword()); + final String result = jwtTokenUtil.doLogin(response, user.getEmail()); - @RequestMapping(value = "/authenticate", method = RequestMethod.POST) - public ResponseEntity createAuthenticationToken(@RequestBody RestJwtUser user, @NotNull HttpServletResponse response) throws Exception { + return ResponseEntity.ok(result); + } - // Is a valid user ? - authenticate(user.getEmail(), user.getPassword()); - - // Create token ... - final UserDetails userDetails = userDetailsService - .loadUserByUsername(user.getEmail()); - - final String token = jwtTokenUtil.generateJwtToken(userDetails); - - // Add token in the header ... - response.addHeader(HttpHeaders.AUTHORIZATION, "Bearer " + token); - - return ResponseEntity.ok(token); - } - - private void authenticate(@NotNull String username, @NotNull String password) throws Exception { - try { - authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password)); - } catch (DisabledException e) { - throw new Exception("USER_DISABLED", e); - } catch (BadCredentialsException e) { - throw new Exception("INVALID_CREDENTIALS", e); - } - } + private void authenticate(@NotNull String username, @NotNull String password) throws WiseMappingException { + try { + authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password)); + } catch (DisabledException | BadCredentialsException e) { + throw new WiseMappingException(e.getMessage(), e); + } + } } \ No newline at end of file diff --git a/wise-api/src/main/java/com/wisemapping/rest/OAuth2Controller.java b/wise-api/src/main/java/com/wisemapping/rest/OAuth2Controller.java index 7427070d..25bc74ef 100644 --- a/wise-api/src/main/java/com/wisemapping/rest/OAuth2Controller.java +++ b/wise-api/src/main/java/com/wisemapping/rest/OAuth2Controller.java @@ -21,68 +21,60 @@ package com.wisemapping.rest; import com.wisemapping.exceptions.WiseMappingException; import com.wisemapping.model.User; import com.wisemapping.rest.model.RestOath2CallbackResponse; -import com.wisemapping.service.*; +import com.wisemapping.security.JwtTokenUtil; +import com.wisemapping.service.UserService; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken; -import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpSession; - @RestController +@RequestMapping("/api/oauth2/") @CrossOrigin public class OAuth2Controller extends BaseController { - @Qualifier("userService") - @Autowired - private UserService userService; + @Qualifier("userService") + @Autowired + private UserService userService; - @Qualifier("authenticationManager") - @Autowired - private AuthenticationManager authManager; + @Qualifier("authenticationManager") + @Autowired + private AuthenticationManager authManager; - @Value("${google.recaptcha2.enabled}") - private Boolean recatchaEnabled; + @Autowired + private JwtTokenUtil jwtTokenUtil; - @Value("${accounts.exclusion.domain:''}") - private String domainBanExclusion; - private void doLogin(HttpServletRequest request, String email) { - PreAuthenticatedAuthenticationToken token = new PreAuthenticatedAuthenticationToken(email,null); - Authentication auth = authManager.authenticate(token); - SecurityContextHolder.getContext().setAuthentication(auth); - // update spring mvc session - HttpSession session = request.getSession(true); - session.setAttribute("SPRING_SECURITY_CONTEXT", SecurityContextHolder.getContext()); - } + @RequestMapping(method = RequestMethod.POST, value = "googlecallback", produces = {"application/json"}) + @ResponseStatus(value = HttpStatus.OK) + public RestOath2CallbackResponse processGoogleCallback(@NotNull @RequestParam String code, @NotNull HttpServletResponse response, @NotNull HttpServletRequest request) throws WiseMappingException { + User user = userService.createAndAuthUserFromGoogle(code); + if (user.getGoogleSync()) { + jwtTokenUtil.doLogin(response, user.getEmail()); + } - @RequestMapping(method = RequestMethod.POST, value = "/oauth2/googlecallback", produces = { "application/json" }) - @ResponseStatus(value = HttpStatus.OK) - public RestOath2CallbackResponse processGoogleCallback(@NotNull @RequestParam String code, @NotNull HttpServletRequest request) throws WiseMappingException { - User user = userService.createUserFromGoogle(code); - if (user.getGoogleSync() != null && user.getGoogleSync()) { - doLogin(request, user.getEmail()); - } - RestOath2CallbackResponse response = new RestOath2CallbackResponse(); - response.setEmail(user.getEmail()); - response.setGoogleSync(user.getGoogleSync()); - response.setSyncCode(user.getSyncCode()); - return response; - } + // Response ... + final RestOath2CallbackResponse result = new RestOath2CallbackResponse(); + result.setEmail(user.getEmail()); + result.setGoogleSync(user.getGoogleSync()); + result.setSyncCode(user.getSyncCode()); + return result; + } - @RequestMapping(method = RequestMethod.PUT, value = "/oauth2/confirmaccountsync", produces = { "application/json" }) - @ResponseStatus(value = HttpStatus.OK) - public void confirmAccountSync(@NotNull @RequestParam String email, @NotNull @RequestParam String code, @NotNull HttpServletRequest request) throws WiseMappingException { - userService.confirmAccountSync(email, code); - doLogin(request, email); - } + @RequestMapping(method = RequestMethod.PUT, value = "confirmaccountsync", produces = {"application/json"}) + @ResponseStatus(value = HttpStatus.OK) + public void confirmAccountSync(@NotNull @RequestParam String email, @NotNull @RequestParam String code, @NotNull HttpServletResponse response) throws WiseMappingException { + // Authenticate ... + userService.createAndAuthUserFromGoogle(code); + // Update login + userService.confirmAccountSync(email, code); + + // Add header ... + jwtTokenUtil.doLogin(response, email); + } } diff --git a/wise-api/src/main/java/com/wisemapping/security/JwtTokenUtil.java b/wise-api/src/main/java/com/wisemapping/security/JwtTokenUtil.java index c33b7472..ef710352 100644 --- a/wise-api/src/main/java/com/wisemapping/security/JwtTokenUtil.java +++ b/wise-api/src/main/java/com/wisemapping/security/JwtTokenUtil.java @@ -3,11 +3,14 @@ package com.wisemapping.security; import io.jsonwebtoken.*; import io.jsonwebtoken.io.Decoders; import io.jsonwebtoken.security.Keys; +import jakarta.servlet.http.HttpServletResponse; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpHeaders; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.stereotype.Component; @@ -18,6 +21,8 @@ import java.util.Date; @Component public class JwtTokenUtil implements Serializable { final private Logger logger = LogManager.getLogger(); + public final static String BEARER_TOKEN_PREFIX = "Bearer "; + @Value("${app.jwt.secret}") private String jwtSecret; @@ -25,6 +30,10 @@ public class JwtTokenUtil implements Serializable { @Value("${app.jwt.expirationMin}") private int jwtExpirationMin; + @Autowired + private UserDetailsService userDetailsService; + + public String generateJwtToken(@NotNull final UserDetails user) { return Jwts.builder() .setSubject((user.getUsername())) @@ -63,4 +72,15 @@ public class JwtTokenUtil implements Serializable { logger.trace("Is JWT token valid:" + result); return result; } + + @NotNull + public String doLogin(@NotNull HttpServletResponse response, @NotNull String email) { + final UserDetails userDetails = userDetailsService.loadUserByUsername(email); + + // Add JWT in the HTTP header ... + final String token = generateJwtToken(userDetails); + response.addHeader(HttpHeaders.AUTHORIZATION, BEARER_TOKEN_PREFIX + token); + + return token; + } } \ No newline at end of file diff --git a/wise-api/src/main/java/com/wisemapping/service/UserService.java b/wise-api/src/main/java/com/wisemapping/service/UserService.java index 6fbda735..46f995b4 100755 --- a/wise-api/src/main/java/com/wisemapping/service/UserService.java +++ b/wise-api/src/main/java/com/wisemapping/service/UserService.java @@ -30,7 +30,7 @@ public interface UserService { User createUser(@NotNull User user, boolean emailConfirmEnabled, boolean welcomeEmail) throws WiseMappingException; - User createUserFromGoogle(@NotNull String callbackCode) throws WiseMappingException; + User createAndAuthUserFromGoogle(@NotNull String callbackCode) throws WiseMappingException; User confirmAccountSync(@NotNull String email, @NotNull String code) throws WiseMappingException; diff --git a/wise-api/src/main/java/com/wisemapping/service/UserServiceImpl.java b/wise-api/src/main/java/com/wisemapping/service/UserServiceImpl.java index 60cd0b44..bce28ff8 100755 --- a/wise-api/src/main/java/com/wisemapping/service/UserServiceImpl.java +++ b/wise-api/src/main/java/com/wisemapping/service/UserServiceImpl.java @@ -161,7 +161,6 @@ public class UserServiceImpl final Mindmap mindMap = buildTutorialMindmap(user.getFirstname()); mindmapService.addMindmap(mindMap, user); - // Send registration email. if (emailConfirmEnabled) { notificationService.sendRegistrationEmail(user); @@ -174,7 +173,7 @@ public class UserServiceImpl } @NotNull - public User createUserFromGoogle(@NotNull String callbackCode) throws WiseMappingException { + public User createAndAuthUserFromGoogle(@NotNull String callbackCode) throws WiseMappingException { GoogleAccountBasicData data; try { data = googleService.processCallback(callbackCode); @@ -185,7 +184,7 @@ public class UserServiceImpl User existingUser = userManager.getUserBy(data.getEmail()); if (existingUser == null) { User newUser = new User(); - // new registrations from google starts synched + // new registrations from google starts sync newUser.setGoogleSync(true); newUser.setEmail(data.getEmail()); newUser.setFirstname(data.getName()); @@ -208,7 +207,7 @@ public class UserServiceImpl } public User confirmAccountSync(@NotNull String email, @NotNull String code) throws WiseMappingException { - User existingUser = userManager.getUserBy(email); + final User existingUser = userManager.getUserBy(email); // additional security check if (existingUser == null || !existingUser.getSyncCode().equals(code)) { throw new WiseMappingException("User not found / incorrect code"); diff --git a/wise-api/src/main/java/com/wisemapping/service/google/GoogleService.java b/wise-api/src/main/java/com/wisemapping/service/google/GoogleService.java index 8bbb6267..6dbe36d0 100644 --- a/wise-api/src/main/java/com/wisemapping/service/google/GoogleService.java +++ b/wise-api/src/main/java/com/wisemapping/service/google/GoogleService.java @@ -34,15 +34,15 @@ import com.wisemapping.service.google.http.HttpInvokerException; public class GoogleService { @Autowired private HttpInvoker httpInvoker; - @Value("${security.oauth2.google.confirmUrl:}") + @Value("${app.security.oauth2.google.confirmUrl:}") private String optinConfirmUrl; - @Value("${security.oauth2.google.userinfoUrl:}") + @Value("${app.security.oauth2.google.userinfoUrl:}") private String accountBasicDataUrl; - @Value("${security.oauth2.google.clientId:}") + @Value("${app.security.oauth2.google.clientId:}") private String clientId; - @Value("${security.oauth2.google.clientSecret:}") + @Value("${app.security.oauth2.google.clientSecret:}") private String clientSecret; - @Value("${security.oauth2.google.callbackUrl:}") + @Value("${app.security.oauth2.google.callbackUrl:}") private String callbackUrl; public void setHttpInvoker(HttpInvoker httpInvoker) { @@ -108,8 +108,9 @@ public class GoogleService { public GoogleAccountBasicData processCallback(final String code) throws HttpInvokerException { - Map body = this.getOptinConfirmBody(code); - JsonNode optionConfirmResponse = httpInvoker.invoke( + + final Map body = this.getOptinConfirmBody(code); + final JsonNode optionConfirmResponse = httpInvoker.invoke( optinConfirmUrl, HttpInvokerContentType.FORM_ENCODED, HttpMethod.POST, @@ -120,7 +121,7 @@ public class GoogleService { final String accessToken = getNodeAsString(optionConfirmResponse, "access_token"); final String refreshToken = getNodeAsString(optionConfirmResponse, "refresh_token"); - GoogleAccountBasicData data = this.getAccountBasicData(accessToken); + final GoogleAccountBasicData data = this.getAccountBasicData(accessToken); data.setAccessToken(accessToken); data.setRefreshToken(refreshToken); return data; diff --git a/wise-api/src/main/java/com/wisemapping/webmvc/MvcLoginController.java b/wise-api/src/main/java/com/wisemapping/webmvc/MvcLoginController.java deleted file mode 100644 index 6f12760d..00000000 --- a/wise-api/src/main/java/com/wisemapping/webmvc/MvcLoginController.java +++ /dev/null @@ -1,46 +0,0 @@ -/* -* Copyright [2022] [wisemapping] -* -* Licensed under WiseMapping Public License, Version 1.0 (the "License"). -* It is basically the Apache License, Version 2.0 (the "License") plus the -* "powered by wisemapping" text requirement on every single page; -* you may not use this file except in compliance with the License. -* You may obtain a copy of the license at -* -* http://www.wisemapping.org/license -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package com.wisemapping.webmvc; - -import com.wisemapping.model.User; -import com.wisemapping.security.Utils; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.servlet.ModelAndView; - -@Controller -@PreAuthorize("permitAll()") -public class MvcLoginController { - - - @RequestMapping(value = "c/login", method = RequestMethod.GET) - protected ModelAndView showLoginPage() { - final User user = Utils.getUser(false); - ModelAndView result; - if (user != null) { - result = new ModelAndView("forward:/c/maps/"); - } else { - result = new ModelAndView("reactInclude"); - } - return result; - } -} diff --git a/wise-api/src/main/resources/application.yml b/wise-api/src/main/resources/application.yml index 38d3c5c5..ad13ef60 100644 --- a/wise-api/src/main/resources/application.yml +++ b/wise-api/src/main/resources/application.yml @@ -60,15 +60,28 @@ app: mail: serverSendEmail: root@localhost supportEmail: root@localhost + + ####################################################################################### + # Google OAuth Authentication + ####################################################################################### + # OAuth Client id + #security.oauth2.google.clientId= + # OAuth Client secret + #security.oauth2.google.clientSecret= + # Redirect to this url, this url must be configured in the google app {baseurl}/c/registration-google + #security.oauth2.google.callbackUrl= + security: + oauth2: + google: + confirmUrl: https://oauth2.googleapis.com/token + userinfoUrl: https://www:googleapis.com/oauth2/v3/userinfo + url: https://accounts.google.com/o/oauth2/v2/auth?redirect_uri=${app.security.oauth2.google.callbackUrl}&prompt=consent&response_type=code&client_id=${app.security.oauth2.google.clientId}&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email&access_type=offline&state=wisemapping&include_granted_scopes=true + # accounts: # exclusion: # domain: - - - - google: ads: enabled: false @@ -79,12 +92,6 @@ google: enabled: true secretKey: 6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe siteKey: 6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI -security: - oauth2: - google: - confirmUrl: https://oauth2.googleapis.com/token - url: https//review - userinfoUrl: https://www.googleapis.com/oauth2/v3/userinfo site: homepage: c/login static: