diff --git a/authenticator/src/main/java/org/openmbee/mms/authenticator/config/AuthSecurityConfig.java b/authenticator/src/main/java/org/openmbee/mms/authenticator/config/AuthSecurityConfig.java index b1a8b452f..627c649c7 100644 --- a/authenticator/src/main/java/org/openmbee/mms/authenticator/config/AuthSecurityConfig.java +++ b/authenticator/src/main/java/org/openmbee/mms/authenticator/config/AuthSecurityConfig.java @@ -19,8 +19,7 @@ public class AuthSecurityConfig { private static Logger logger = LoggerFactory.getLogger(AuthSecurityConfig.class); @Autowired - public void setAuthProvider(AuthenticationManagerBuilder auth, - JwtAuthenticationProvider provider) { + public void setAuthProvider(AuthenticationManagerBuilder auth, JwtAuthenticationProvider provider) { auth.authenticationProvider(provider); } diff --git a/example/src/main/java/org/openmbee/mms/example/config/ExampleSecurityConfig.java b/example/src/main/java/org/openmbee/mms/example/config/ExampleSecurityConfig.java index ac7f771a1..d7ccd3397 100644 --- a/example/src/main/java/org/openmbee/mms/example/config/ExampleSecurityConfig.java +++ b/example/src/main/java/org/openmbee/mms/example/config/ExampleSecurityConfig.java @@ -2,6 +2,7 @@ import org.openmbee.mms.authenticator.config.AuthSecurityConfig; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.MediaType; @@ -31,6 +32,9 @@ @EnableAsync public class ExampleSecurityConfig extends WebSecurityConfigurerAdapter implements WebMvcConfigurer { + @Value("${cors.allowed.origins:*}") + private String allowedOrigins; + @Autowired AuthSecurityConfig authSecurityConfig; @@ -57,7 +61,7 @@ public AuthenticationManager authenticationManagerBean() throws Exception { @Override public void addCorsMappings(CorsRegistry registry) { - registry.addMapping("/**").allowedMethods("GET", "POST", "PUT", "DELETE"); + registry.addMapping("/**").allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS"); } private CorsFilter corsFilter() { @@ -70,7 +74,9 @@ private CorsFilter corsFilter() { CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); - config.addAllowedOrigin("*"); + for(String origin: allowedOrigins.split(",")) { + config.addAllowedOrigin(origin); + } config.addAllowedHeader(ORIGIN); config.addAllowedHeader(CONTENT_TYPE); config.addAllowedHeader(ACCEPT); diff --git a/example/src/main/resources/application-test.properties b/example/src/main/resources/application-test.properties index 2a9b572e1..f36a8f0c7 100644 --- a/example/src/main/resources/application-test.properties +++ b/example/src/main/resources/application-test.properties @@ -4,6 +4,8 @@ mms.admin.password=test mms.stream.batch.size=100000 +cors.allowed.origins=* + jwt.secret=12345678901234567890123456789012 jwt.expiration=86400 jwt.header=Authorization diff --git a/example/src/main/resources/application.properties.example b/example/src/main/resources/application.properties.example index 339250a5f..128954249 100644 --- a/example/src/main/resources/application.properties.example +++ b/example/src/main/resources/application.properties.example @@ -4,23 +4,26 @@ mms.admin.password=test mms.stream.batch.size=100000 +#Comma Separated list of allowed cross site origins +cors.allowed.origins=* + jwt.secret=make_me_something_really_long jwt.expiration=86400 jwt.header=Authorization # See ldap module for example configuration -ldap.provider.base=ou=something,dc=openmbee,dc=org -ldap.provider.url=ldaps://ldap.openmbee.org/${ldap.provider.base} +ldap.provider.base=dc=directory,dc=openmbee,dc=org +ldap.provider.url=ldaps://ldap.openmbee.org ldap.provider.userdn= ldap.provider.password= -ldap.user.dn.pattern=uid={0} +ldap.user.dn.pattern=uid={0},ou=personnel ldap.user.attributes.username= ldap.user.attributes.email= ldap.user.attributes.firstname= ldap.user.attributes.lastname= ldap.user.attributes.update=24 ldap.group.role.attribute=cn -ldap.group.search.base= +ldap.group.search.base=ou=groups ldap.group.search.filter=uniqueMember={0} # See core module for example configuration diff --git a/gradle.properties b/gradle.properties index 8be66ab85..6c5dbbab5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=4.0.8 +version=4.0.9 group=org.openmbee.mms springBootVersion=2.6.7 diff --git a/ldap/src/main/java/org/openmbee/mms/ldap/LdapSecurityConfig.java b/ldap/src/main/java/org/openmbee/mms/ldap/LdapSecurityConfig.java index 01bde33e6..8f0adc6f4 100644 --- a/ldap/src/main/java/org/openmbee/mms/ldap/LdapSecurityConfig.java +++ b/ldap/src/main/java/org/openmbee/mms/ldap/LdapSecurityConfig.java @@ -5,7 +5,6 @@ import java.util.*; import org.openmbee.mms.core.config.AuthorizationConstants; -import org.openmbee.mms.data.domains.global.Base; import org.openmbee.mms.data.domains.global.Group; import org.openmbee.mms.rdb.repositories.GroupRepository; import org.openmbee.mms.rdb.repositories.UserRepository; @@ -20,12 +19,12 @@ import org.springframework.context.annotation.Configuration; import org.springframework.ldap.core.DirContextOperations; import org.springframework.ldap.core.support.BaseLdapPathContextSource; +import org.springframework.ldap.core.support.LdapContextSource; import org.springframework.ldap.filter.*; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.ldap.DefaultSpringSecurityContextSource; import org.springframework.security.ldap.SpringSecurityLdapTemplate; import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator; import org.springframework.transaction.annotation.EnableTransactionManagement; @@ -113,11 +112,11 @@ LdapAuthoritiesPopulator ldapAuthoritiesPopulator(@Qualifier("contextSource") Ba /* Specificity here : we don't get the Role by reading the members of available groups (which is implemented by - default in Spring security LDAP), but we retrieve the groups from the field memberOf of the user. + default in Spring security LDAP), but we retrieve the groups the user belongs to. */ class CustomLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator { - SpringSecurityLdapTemplate ldapTemplate; + final SpringSecurityLdapTemplate ldapTemplate; private CustomLdapAuthoritiesPopulator(BaseLdapPathContextSource ldapContextSource) { ldapTemplate = new SpringSecurityLdapTemplate(ldapContextSource); @@ -126,11 +125,12 @@ private CustomLdapAuthoritiesPopulator(BaseLdapPathContextSource ldapContextSour @Override public Collection getGrantedAuthorities( DirContextOperations userData, String username) { + logger.debug("Populating authorities using LDAP"); Optional userOptional = userRepository.findByUsername(username); - if (!userOptional.isPresent()) { + if (userOptional.isEmpty()) { + logger.info("No user record for {} in the userRepository, creating...", userData.getDn()); User newUser = createLdapUser(userData); - userOptional = Optional.of(newUser); } @@ -139,13 +139,20 @@ public Collection getGrantedAuthorities( saveLdapUser(userData, user); } user.setPassword(null); - String userDn = userAttributesUsername + "=" + user.getUsername() + "," + providerBase; + + StringBuilder userDnBuilder = new StringBuilder(); + userDnBuilder.append(userData.getDn().toString()); + if (providerBase != null && !providerBase.isEmpty()) { + userDnBuilder.append(','); + userDnBuilder.append(providerBase); + } + String userDn = userDnBuilder.toString(); List definedGroups = groupRepository.findAll(); OrFilter orFilter = new OrFilter(); - for (int i = 0; i < definedGroups.size(); i++) { - orFilter.or(new EqualsFilter(groupRoleAttribute, definedGroups.get(i).getName())); + for (Group definedGroup : definedGroups) { + orFilter.or(new EqualsFilter(groupRoleAttribute, definedGroup.getName())); } AndFilter andFilter = new AndFilter(); @@ -154,15 +161,29 @@ public Collection getGrantedAuthorities( andFilter.and(groupsFilter); andFilter.and(orFilter); + String filter = andFilter.encode(); + logger.debug("Searching LDAP with filter: {}", filter); + Set memberGroups = ldapTemplate - .searchForSingleAttributeValues("", andFilter.encode(), new Object[]{""}, - groupRoleAttribute); + .searchForSingleAttributeValues(groupSearchBase, filter, new Object[]{""}, groupRoleAttribute); + logger.debug("LDAP search result: {}", Arrays.toString(memberGroups.toArray())); Set addGroups = new HashSet<>(); for (String memberGroup : memberGroups) { Optional group = groupRepository.findByName(memberGroup); group.ifPresent(addGroups::add); } + + if (logger.isDebugEnabled()) { + if ((long) addGroups.size() > 0) { + addGroups.forEach(group -> { + logger.debug("Group received: {}", group.getName()); + }); + } else { + logger.debug("No configured groups returned from LDAP"); + } + } + user.setGroups(addGroups); userRepository.save(user); @@ -181,11 +202,19 @@ public Collection getGrantedAuthorities( } @Bean - public BaseLdapPathContextSource contextSource() { - DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource( - providerUrl); + public LdapContextSource contextSource() { + LdapContextSource contextSource = new LdapContextSource(); + + logger.debug("Initializing LDAP ContextSource with the following values: "); + + contextSource.setUrl(providerUrl); + contextSource.setBase(providerBase); contextSource.setUserDn(providerUserDn); contextSource.setPassword(providerPassword); + + logger.debug("BaseLdapPath: " + contextSource.getBaseLdapPathAsString()); + logger.debug("UserDn: " + contextSource.getUserDn()); + return contextSource; } @@ -210,13 +239,14 @@ private User saveLdapUser(DirContextOperations userData, User saveUser) { } private User createLdapUser(DirContextOperations userData) { + String username = userData.getStringAttribute(userAttributesUsername); + logger.debug("Creating user for {} using LDAP", username); User user = saveLdapUser(userData, new User()); - user.setUsername(userData.getStringAttribute(userAttributesUsername)); + user.setUsername(username); user.setEnabled(true); user.setAdmin(false); userRepository.save(user); - return user; } } \ No newline at end of file