Fix login bug.

This commit is contained in:
Paulo Gustavo Veiga 2024-02-07 00:04:06 -08:00
parent 56c322fd3f
commit 885de4e1c1
5 changed files with 147 additions and 83 deletions

View File

@ -11,8 +11,10 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter; import org.springframework.web.filter.OncePerRequestFilter;
@ -43,13 +45,13 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
if (email.isPresent() && jwtTokenUtil.validateJwtToken(token.get())) { if (email.isPresent() && jwtTokenUtil.validateJwtToken(token.get())) {
// Is it an existing user ? // Is it an existing user ?
final UserDetails userDetails = userDetailsService.loadUserByUsername(email.get()); try {
if (userDetails != null) { final UserDetails userDetails = userDetailsService.loadUserByUsername(email.get());
final UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken( final UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities()); userDetails, null, userDetails.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken); SecurityContextHolder.getContext().setAuthentication(authenticationToken);
} else { } catch (UsernameNotFoundException e) {
logger.trace("User " + email.get() + " could not be found"); logger.trace("User " + email.get() + " could not be found");
} }
} }

View File

@ -69,7 +69,7 @@ public class MindmapController extends BaseController {
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')") @PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.GET, value = "/{id}", produces = {"application/json"}) @RequestMapping(method = RequestMethod.GET, value = "/{id}", produces = {"application/json"})
@ResponseBody @ResponseBody
public RestMindmap retrieve(@PathVariable int id) throws WiseMappingException { public RestMindmap retrieve(@PathVariable int id) throws WiseMappingException {
final User user = Utils.getUser(); final User user = Utils.getUser();
@ -77,6 +77,16 @@ public class MindmapController extends BaseController {
return new RestMindmap(mindMap, user); return new RestMindmap(mindMap, user);
} }
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.GET, value = "/{id}/metadata", produces = {"application/json"})
@ResponseBody
public RestMindmap retrieveMetadata(@PathVariable int id) throws WiseMappingException {
final User user = Utils.getUser();
final Mindmap mindMap = findMindmapById(id);
return new RestMindmap(mindMap, user);
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')") @PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.GET, value = "/", produces = {"application/json"}) @RequestMapping(method = RequestMethod.GET, value = "/", produces = {"application/json"})
public RestMindmapList retrieveList(@RequestParam(required = false) String q) { public RestMindmapList retrieveList(@RequestParam(required = false) String q) {

View File

@ -51,100 +51,102 @@ import java.util.List;
@RequestMapping("/api/restful/users") @RequestMapping("/api/restful/users")
public class UserController extends BaseController { public class UserController extends BaseController {
@Qualifier("userService") @Qualifier("userService")
@Autowired @Autowired
private UserService userService; private UserService userService;
@Autowired @Autowired
private RecaptchaService captchaService; private RecaptchaService captchaService;
@Qualifier("authenticationManager") @Qualifier("authenticationManager")
@Autowired @Autowired
private AuthenticationManager authManager; private AuthenticationManager authManager;
@Value("${google.recaptcha2.enabled:false}") @Value("${google.recaptcha2.enabled:false}")
private Boolean recatchaEnabled; private Boolean recatchaEnabled;
@Value("${accounts.exclusion.domain:''}") @Value("${app.accounts.exclusion.domain:''}")
private String domainBanExclusion; private String domainBanExclusion;
private static final Logger logger = LogManager.getLogger(); private static final Logger logger = LogManager.getLogger();
private static final String REAL_IP_ADDRESS_HEADER = "X-Real-IP"; private static final String REAL_IP_ADDRESS_HEADER = "X-Real-IP";
@RequestMapping(method = RequestMethod.POST, value = "/", produces = { "application/json" }) @RequestMapping(method = RequestMethod.POST, value = "/", produces = {"application/json"})
@ResponseStatus(value = HttpStatus.CREATED) @ResponseStatus(value = HttpStatus.CREATED)
public void registerUser(@RequestBody RestUserRegistration registration, @NotNull HttpServletRequest request, public void registerUser(@RequestBody RestUserRegistration registration, @NotNull HttpServletRequest request,
@NotNull HttpServletResponse response) throws WiseMappingException, BindException { @NotNull HttpServletResponse response) throws WiseMappingException, BindException {
logger.debug("Register new user:" + registration.getEmail()); logger.debug("Register new user:" + registration.getEmail());
if (registration.getPassword().length() > User.MAX_PASSWORD_LENGTH_SIZE) { if (registration.getPassword().length() > User.MAX_PASSWORD_LENGTH_SIZE) {
throw new PasswordTooLongException(); throw new PasswordTooLongException();
} }
// If tomcat is behind a reverse proxy, ip needs to be found in other header. // If tomcat is behind a reverse proxy, ip needs to be found in other header.
String remoteIp = request.getHeader(REAL_IP_ADDRESS_HEADER); String remoteIp = request.getHeader(REAL_IP_ADDRESS_HEADER);
if (remoteIp == null || remoteIp.isEmpty()) { if (remoteIp == null || remoteIp.isEmpty()) {
remoteIp = request.getRemoteAddr(); remoteIp = request.getRemoteAddr();
} }
logger.debug("Remote address" + remoteIp); logger.debug("Remote address" + remoteIp);
verify(registration, remoteIp); verify(registration, remoteIp);
final User user = new User(); final User user = new User();
user.setEmail(registration.getEmail().trim()); user.setEmail(registration.getEmail().trim());
user.setFirstname(registration.getFirstname()); user.setFirstname(registration.getFirstname());
user.setLastname(registration.getLastname()); user.setLastname(registration.getLastname());
user.setPassword(registration.getPassword()); user.setPassword(registration.getPassword());
user.setAuthenticationType(AuthenticationType.DATABASE); user.setAuthenticationType(AuthenticationType.DATABASE);
userService.createUser(user, false, true); userService.createUser(user, false, true);
response.setHeader("Location", "/api/restful/users/" + user.getId()); response.setHeader("Location", "/api/restful/users/" + user.getId());
} response.setHeader("ResourceId", Integer.toString(user.getId()));
@RequestMapping(method = RequestMethod.PUT, value = "/resetPassword", produces = { "application/json" }) }
@ResponseStatus(value = HttpStatus.OK)
public RestResetPasswordResponse resetPassword(@RequestParam String email) throws InvalidAuthSchemaException, EmailNotExistsException {
try {
return userService.resetPassword(email);
} catch (InvalidUserEmailException e) {
throw new EmailNotExistsException(e);
}
}
private void verify(@NotNull final RestUserRegistration registration, @NotNull String remoteAddress) @RequestMapping(method = RequestMethod.PUT, value = "/resetPassword", produces = {"application/json"})
throws BindException { @ResponseStatus(value = HttpStatus.OK)
public RestResetPasswordResponse resetPassword(@RequestParam String email) throws InvalidAuthSchemaException, EmailNotExistsException {
try {
return userService.resetPassword(email);
} catch (InvalidUserEmailException e) {
throw new EmailNotExistsException(e);
}
}
final BindException errors = new RegistrationException(registration, "registration"); private void verify(@NotNull final RestUserRegistration registration, @NotNull String remoteAddress)
final UserValidator validator = new UserValidator(); throws BindException {
validator.setUserService(userService);
validator.validate(registration, errors);
// If captcha is enabled, generate it ... final BindException errors = new RegistrationException(registration, "registration");
if (recatchaEnabled) { final UserValidator validator = new UserValidator();
final String recaptcha = registration.getRecaptcha(); validator.setUserService(userService);
if (recaptcha != null) { validator.validate(registration, errors);
final String reCaptchaResponse = captchaService.verifyRecaptcha(remoteAddress, recaptcha);
if (reCaptchaResponse != null && !reCaptchaResponse.isEmpty()) {
errors.rejectValue("recaptcha", reCaptchaResponse);
}
} else {
errors.rejectValue("recaptcha", Messages.CAPTCHA_LOADING_ERROR);
}
} else {
logger.warn("captchaEnabled is enabled.Recommend to enable it for production environments.");
}
if (errors.hasErrors()) { // If captcha is enabled, generate it ...
throw errors; if (recatchaEnabled) {
} final String recaptcha = registration.getRecaptcha();
if (recaptcha != null) {
final String reCaptchaResponse = captchaService.verifyRecaptcha(remoteAddress, recaptcha);
if (reCaptchaResponse != null && !reCaptchaResponse.isEmpty()) {
errors.rejectValue("recaptcha", reCaptchaResponse);
}
} else {
errors.rejectValue("recaptcha", Messages.CAPTCHA_LOADING_ERROR);
}
} else {
logger.warn("captchaEnabled is enabled.Recommend to enable it for production environments.");
}
// Is excluded ?. if (errors.hasErrors()) {
final List<String> excludedDomains = Arrays.asList(domainBanExclusion.split(",")); throw errors;
final String emailDomain = registration.getEmail().split("@")[1]; }
if (excludedDomains.contains(emailDomain)) {
throw new IllegalArgumentException( // Is excluded ?.
"Email is part of ban exclusion list due to abuse. Please, contact site admin if you think this is an error." final List<String> excludedDomains = Arrays.asList(domainBanExclusion.split(","));
+ emailDomain); final String emailDomain = registration.getEmail().split("@")[1];
} if (excludedDomains.contains(emailDomain)) {
} throw new IllegalArgumentException(
"Email is part of ban exclusion list due to abuse. Please, contact site admin if you think this is an error."
+ emailDomain);
}
}
} }

View File

@ -0,0 +1,47 @@
/*
* 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.rest.model;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.wisemapping.exceptions.InvalidMindmapException;
import com.wisemapping.exceptions.WiseMappingException;
import com.wisemapping.model.*;
import com.wisemapping.util.TimeUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.util.Calendar;
@JsonAutoDetect(
fieldVisibility = JsonAutoDetect.Visibility.NONE,
setterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY,
isGetterVisibility = JsonAutoDetect.Visibility.NONE,
getterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY
)
@JsonIgnoreProperties(ignoreUnknown = true)
public class RestMindmapMetadata {
public RestMindmapMetadata() throws WiseMappingException {
}
}

View File

@ -58,6 +58,9 @@ app:
mail: mail:
serverSendEmail: root@localhost serverSendEmail: root@localhost
supportEmail: root@localhost supportEmail: root@localhost
# accounts:
# exclusion:
# domain: