From 3e9a5a0b1260f62e0fc684b1a91f91f735a794f1 Mon Sep 17 00:00:00 2001 From: Paulo Gustavo Veiga Date: Mon, 11 Apr 2022 17:50:19 -0300 Subject: [PATCH] Add exclusion list for domains. --- .../com/wisemapping/rest/AdminController.java | 43 ++++++----- .../wisemapping/rest/MindmapController.java | 7 +- .../com/wisemapping/rest/UserController.java | 12 ++++ .../security/AuthenticationProvider.java | 6 ++ .../security/UserDetailsService.java | 72 +------------------ .../src/main/webapp/WEB-INF/app.properties | 5 ++ 6 files changed, 49 insertions(+), 96 deletions(-) diff --git a/wise-webapp/src/main/java/com/wisemapping/rest/AdminController.java b/wise-webapp/src/main/java/com/wisemapping/rest/AdminController.java index ca516dda..352f5681 100644 --- a/wise-webapp/src/main/java/com/wisemapping/rest/AdminController.java +++ b/wise-webapp/src/main/java/com/wisemapping/rest/AdminController.java @@ -1,20 +1,20 @@ /* -* 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. -*/ + * 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; @@ -26,19 +26,16 @@ import com.wisemapping.model.User; import com.wisemapping.rest.model.RestUser; import com.wisemapping.service.MindmapService; import com.wisemapping.service.UserService; -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.stereotype.Controller; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletResponse; import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.util.Calendar; import java.util.List; -import java.util.regex.Pattern; @Controller public class AdminController extends BaseController { @@ -70,7 +67,7 @@ public class AdminController extends BaseController { return new RestUser(user); } - @RequestMapping(method = RequestMethod.POST, value = "admin/users", consumes = { "application/json"}, produces = {"application/json"}) + @RequestMapping(method = RequestMethod.POST, value = "admin/users", consumes = {"application/json"}, produces = {"application/json"}) @ResponseStatus(value = HttpStatus.CREATED) public void createUser(@RequestBody RestUser user, HttpServletResponse response) throws WiseMappingException { if (user == null) { @@ -109,7 +106,7 @@ public class AdminController extends BaseController { @RequestMapping(method = RequestMethod.PUT, value = "admin/users/{id}/password", consumes = {"text/plain"}) @ResponseStatus(value = HttpStatus.NO_CONTENT) - public void changePassword(@RequestBody String password, @PathVariable int id) throws WiseMappingException { + public void changePassword(@RequestBody String password, @PathVariable int id) throws WiseMappingException { if (password == null) { throw new IllegalArgumentException("Password can not be null"); } @@ -133,7 +130,7 @@ public class AdminController extends BaseController { final List collaborations = mindmapService.findCollaborations(user); for (Collaboration collaboration : collaborations) { final Mindmap mindmap = collaboration.getMindMap(); - mindmapService.removeMindmap(mindmap,user); + mindmapService.removeMindmap(mindmap, user); } userService.removeUser(user); diff --git a/wise-webapp/src/main/java/com/wisemapping/rest/MindmapController.java b/wise-webapp/src/main/java/com/wisemapping/rest/MindmapController.java index 370f7c57..6103a51d 100644 --- a/wise-webapp/src/main/java/com/wisemapping/rest/MindmapController.java +++ b/wise-webapp/src/main/java/com/wisemapping/rest/MindmapController.java @@ -29,6 +29,7 @@ import org.apache.log4j.Logger; 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.http.ResponseEntity; import org.springframework.stereotype.Controller; @@ -48,7 +49,6 @@ public class MindmapController extends BaseController { final Logger logger = Logger.getLogger(MindmapController.class); private static final String LATEST_HISTORY_REVISION = "latest"; - private static final int MAX_ACCOUNTS_INACTIVE = 20; @Qualifier("mindmapService") @Autowired @@ -62,6 +62,9 @@ public class MindmapController extends BaseController { @Autowired private UserService userService; + @Value("${accounts.maxInactive:20}") + private int maxAccountsInactive; + @RequestMapping(method = RequestMethod.GET, value = "/maps/{id}", produces = {"application/json"}) @ResponseBody public RestMindmap retrieve(@PathVariable int id) throws WiseMappingException { @@ -614,7 +617,7 @@ public class MindmapController extends BaseController { .collect(Collectors.toSet())); long inactiveAccounts = allEmails.stream().filter(e -> userService.getUserBy(e) == null).count(); - if (inactiveAccounts > MAX_ACCOUNTS_INACTIVE) { + if (inactiveAccounts > maxAccountsInactive) { throw new TooManyInactiveAccountsExceptions(inactiveAccounts); } } diff --git a/wise-webapp/src/main/java/com/wisemapping/rest/UserController.java b/wise-webapp/src/main/java/com/wisemapping/rest/UserController.java index 64260877..2574ae79 100644 --- a/wise-webapp/src/main/java/com/wisemapping/rest/UserController.java +++ b/wise-webapp/src/main/java/com/wisemapping/rest/UserController.java @@ -38,6 +38,8 @@ import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.util.Arrays; +import java.util.List; @Controller @CrossOrigin @@ -52,6 +54,9 @@ public class UserController extends BaseController { @Value("${google.recaptcha2.enabled}") private Boolean recatchaEnabled; + @Value("${accounts.exclusion.domain:''}") + private String domainBanExclusion; + private static final Logger logger = Logger.getLogger(UserController.class); private static final String REAL_IP_ADDRESS_HEADER = "X-Real-IP"; @@ -115,5 +120,12 @@ public class UserController extends BaseController { if (errors.hasErrors()) { throw errors; } + + // Is excluded ?. + final List excludedDomains = Arrays.asList(domainBanExclusion.split(",")); + 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); + } } } diff --git a/wise-webapp/src/main/java/com/wisemapping/security/AuthenticationProvider.java b/wise-webapp/src/main/java/com/wisemapping/security/AuthenticationProvider.java index a4240d07..00f433f8 100644 --- a/wise-webapp/src/main/java/com/wisemapping/security/AuthenticationProvider.java +++ b/wise-webapp/src/main/java/com/wisemapping/security/AuthenticationProvider.java @@ -45,6 +45,12 @@ public class AuthenticationProvider implements org.springframework.security.auth if (user == null || credentials == null || !encoder.matches(user.getPassword(), credentials)) { throw new BadCredentialsException("Username/Password does not match for " + auth.getPrincipal()); } + + // User has been disabled ... + if (!user.isActive()) { + throw new BadCredentialsException("User has been disabled for login " + auth.getPrincipal()); + } + userDetailsService.getUserService().auditLogin(user); return new UsernamePasswordAuthenticationToken(userDetails, credentials, userDetails.getAuthorities()); } diff --git a/wise-webapp/src/main/java/com/wisemapping/security/UserDetailsService.java b/wise-webapp/src/main/java/com/wisemapping/security/UserDetailsService.java index a400294a..4a32bf35 100644 --- a/wise-webapp/src/main/java/com/wisemapping/security/UserDetailsService.java +++ b/wise-webapp/src/main/java/com/wisemapping/security/UserDetailsService.java @@ -23,6 +23,7 @@ import com.wisemapping.model.User; import com.wisemapping.service.UserService; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.springframework.beans.factory.annotation.Value; import org.springframework.dao.DataAccessException; import org.springframework.security.core.userdetails.UsernameNotFoundException; @@ -43,77 +44,6 @@ public class UserDetailsService } } -// @Override -// @NotNull -// public UserDetails loadUserDetails(@NotNull OpenIDAuthenticationToken token) throws UsernameNotFoundException { -// -// final User tUser = buildUserFromToken(token); -// final User dbUser = userService.getUserBy(tUser.getEmail()); -// -// final User result; -// if (dbUser != null) { -// if (!token.getIdentityUrl().equals(dbUser.getAuthenticatorUri())) { -// throw new IllegalStateException("Identity url for this user can not change:" + token.getIdentityUrl()); -// } -// result = dbUser; -// } else { -// try { -// tUser.setAuthenticationType(AuthenticationType.OPENID); -// tUser.setAuthenticatorUri(token.getIdentityUrl()); -// -// result = userService.createUser(tUser, false, false); -// } catch (WiseMappingException e) { -// throw new IllegalStateException(e); -// } -// -// } -// return new UserDetails(result, isAdmin(result.getEmail())); -// } - -// @NotNull -// private User buildUserFromToken(@NotNull OpenIDAuthenticationToken token) { -// final User result = new User(); -// -// String lastName = null; -// String firstName = null; -// String email = null; -// String fullName = null; -// -// final List attributes = token.getAttributes(); -// for (OpenIDAttribute attribute : attributes) { -// if (attribute.getName().equals("email")) { -// email = attribute.getValues().get(0); -// } -// -// if (attribute.getName().equals("firstname")) { -// firstName = attribute.getValues().get(0); -// -// } -// -// if (attribute.getName().equals("lastname")) { -// lastName = attribute.getValues().get(0); -// } -// -// if (attribute.getName().equals("fullname")) { -// fullName = attribute.getValues().get(0); -// } -// -// } -// if (lastName == null || firstName == null) { -// result.setFirstname(fullName); -// result.setLastname(""); -// } else { -// result.setLastname(lastName); -// result.setFirstname(firstName); -// } -// result.setEmail(email); -// result.setPassword(""); -// -// final Calendar now = Calendar.getInstance(); -// result.setActivationDate(now); -// return result; -// } - private boolean isAdmin(@Nullable String email) { return email != null && adminUser != null && email.trim().endsWith(adminUser); } diff --git a/wise-webapp/src/main/webapp/WEB-INF/app.properties b/wise-webapp/src/main/webapp/WEB-INF/app.properties index 3a01ea34..3cbab059 100755 --- a/wise-webapp/src/main/webapp/WEB-INF/app.properties +++ b/wise-webapp/src/main/webapp/WEB-INF/app.properties @@ -134,6 +134,11 @@ security.ldap.auth.attribute=mail security.ldap.lastName.attribute=sn security.ldap.firstName.attribute=givenName +# User Account filtering policies + +# Coma separated list of domains and emails ban +#accounts.exclusion.domain= +