Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -31,6 +32,9 @@
@EnableAsync
public class ExampleSecurityConfig extends WebSecurityConfigurerAdapter implements WebMvcConfigurer {

@Value("${cors.allowed.origins:*}")
private String allowedOrigins;

@Autowired
AuthSecurityConfig authSecurityConfig;

Expand All @@ -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() {
Expand All @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions example/src/main/resources/application-test.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 7 additions & 4 deletions example/src/main/resources/application.properties.example
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version=4.0.8
version=4.0.9
group=org.openmbee.mms

springBootVersion=2.6.7
Expand Down
62 changes: 46 additions & 16 deletions ldap/src/main/java/org/openmbee/mms/ldap/LdapSecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -126,11 +125,12 @@ private CustomLdapAuthoritiesPopulator(BaseLdapPathContextSource ldapContextSour
@Override
public Collection<? extends GrantedAuthority> getGrantedAuthorities(
DirContextOperations userData, String username) {
logger.debug("Populating authorities using LDAP");
Optional<User> 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);
}

Expand All @@ -139,13 +139,20 @@ public Collection<? extends GrantedAuthority> 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<Group> 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();
Expand All @@ -154,15 +161,29 @@ public Collection<? extends GrantedAuthority> getGrantedAuthorities(
andFilter.and(groupsFilter);
andFilter.and(orFilter);

String filter = andFilter.encode();
logger.debug("Searching LDAP with filter: {}", filter);

Set<String> memberGroups = ldapTemplate
.searchForSingleAttributeValues("", andFilter.encode(), new Object[]{""},
groupRoleAttribute);
.searchForSingleAttributeValues(groupSearchBase, filter, new Object[]{""}, groupRoleAttribute);
logger.debug("LDAP search result: {}", Arrays.toString(memberGroups.toArray()));

Set<Group> addGroups = new HashSet<>();
for (String memberGroup : memberGroups) {
Optional<Group> 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);

Expand All @@ -181,11 +202,19 @@ public Collection<? extends GrantedAuthority> 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;
}

Expand All @@ -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;
}
}