I am using Spring Security with LDAP (Active directory), I am able to authenticate user and create my own user detail object by extending LdapUserDetailsMapper.
By default I am getting certain fields and groups and DN.
But I would like to get additional fields, like email, contact number, which are available in Active Directory.
So how to get those information ?
My configuration
#Bean
public ActiveDirectoryLdapAuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider("hmie.co.in", "ldap://1.1.1.1:389/");
provider.setConvertSubErrorCodesToExceptions(true);
provider.setUseAuthenticationRequestCredentials(true);
provider.setUserDetailsContextMapper(userDetailsContextMapper);
return provider;
}
Custom user detail mapping
#Service
public class MyUserDetailsContextMapper extends LdapUserDetailsMapper implements UserDetailsContextMapper {
#Override
public UserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<? extends GrantedAuthority> authorities) {
LdapUserDetailsImpl ldapUserDetailsImpl = (LdapUserDetailsImpl) super.mapUserFromContext(ctx, username, authorities);
MyUserDetails myUserDetails = new MyUserDetails();
myUserDetails.setAccountNonExpired(ldapUserDetailsImpl.isAccountNonExpired());
myUserDetails.setAccountNonLocked(ldapUserDetailsImpl.isAccountNonLocked());
myUserDetails.setCredentialsNonExpired(ldapUserDetailsImpl.isCredentialsNonExpired());
myUserDetails.setEnabled(ldapUserDetailsImpl.isEnabled());
myUserDetails.setUsername(ldapUserDetailsImpl.getUsername());
myUserDetails.setAuthorities(ldapUserDetailsImpl.getAuthorities());
String dn = ldapUserDetailsImpl.getDn();
int beginIndex = dn.indexOf("cn=") + 3;
int endIndex = dn.indexOf(",");
myUserDetails.setEmployeeName(dn.substring(beginIndex, endIndex));
beginIndex = dn.indexOf("ou=") + 3;
endIndex = dn.indexOf(",", beginIndex);
myUserDetails.setDepartment(dn.substring(beginIndex, endIndex));
return myUserDetails;
}
}
To get the complete LDAP Directory attributes and values i did like this. But here i am using inteface org.springframework.ldap.core.AttributesMapper instead of class org.springframework.security.ldap.userdetails.LdapUserDetailsMapper.
ldapTemplate.search("o=XXXXX", new EqualsFilter("uid", userName).encode(),
new AttributesMapper() {
#Override
public Object mapFromAttributes(Attributes attr) throws NamingException {
// TODO Auto-generated method stub
NamingEnumeration<String> namingEnumeration = attr.getIDs();
while (namingEnumeration.hasMoreElements()) {
String attributeName= (String) namingEnumeration.nextElement();
System.out.println(attributeName+" = "+attr.get(attributeName));
}
return null;
}
});
In the above piece of code attr.getIDs() returns the Active directory attributes like CN,DN,SN and mail. attr.get(attribute) returns the value of attribute.
The code in mapUserFromContext is so close! The key detail is that the ctx object passed in to the method already contains the additional Active Directory attributes for the principal. The attribute values are accessible using method ctx.getStringAttribute("attribute-name"). For example, you would access the surname attribute of the principal with ctx.getStringAttribute("sn"). To get the user's email and contact number, you would only need to access the appropriate attributes. In my company's Active Directory, those attributes are mail and phone, respectively. The attributes might be named differently in your system.
Related
I am trying to use Spring LDAP to retrieve and modify user information in an Active Directory server, but I can't retrieve a user record by dn so that I can modify it.
I am able to find the record by username with the LdapTemplate.search method. There is no dn attribute in the record, but distinguishedName looks like it should be correct. When I use LdapTemplate.lookupContext to retrieve the record by dn, however, the server says that it can't find the record by the dn that it just gave me. What am I doing wrong?
It seem wrong that the LdapTemplate search method doesn't give you a handle that you can use without doing a second query from the Active Directory. Is there a better way to do this?
I have created a sample Groovy application to demonstrate the problem. My Spring Boot application creates this class and then invokes the runTest method.
package edu.sunyjcc.gateway.ldap;
import javax.naming.Name;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import javax.naming.ldap.LdapName;
import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.LdapTemplate;
import static org.springframework.ldap.query.LdapQueryBuilder.query;
import org.springframework.ldap.core.DirContextOperations;
public class ActiveDirectoryDNSample {
LdapTemplate ldapTemplate;
/** Attributes to fetch from server */
static attributeList = [
"sAMAccountName",
"distinguishedName",
"baseDn",
"userPrincipalName",
];
/** This will represent the record retrieved from Active Directory */
class Person {
/** Raw data from server */
Map attributes = [:];
/** Return the distinguished name */
String getDn() {
attributes?.distinguishedName;
}
String getUsername() {
attributes?.sAMAccountName;
}
String toString() {
"${this.username} <${this.getDn()}>"
}
/** Get a handle to the object from AD so we can modify it. This fails. */
def getContext() {
assert ldapTemplate;
println "in getContext()";
def dn = new LdapName(this.getDn());
println "...dn=$dn"
assert dn;
// The next line throws an exception.
DirContextOperations context = ldapTemplate.lookupContext(dn);
println "...context=$context"
}
}
/** Convert the attributes from AD into a Person object */
class RecordMapper implements AttributesMapper<Person> {
/** Create a Person object from the attribute map */
Person mapFromAttributes(Attributes attributes)
throws NamingException {
assert ldapTemplate;
Person prec = new Person(
ldapTemplate: ldapTemplate
);
attributeList.collect {
[attrName: it, attr: attributes.get(it)]
}.grep {it.attr}.each {
prec.attributes."${it.attrName}" = it.attr.get() as String;
}
return prec;
}
}
/** Get a user from Active Directory */
public List<Person> getByUsername(String username) throws Exception {
assert ldapTemplate;
AttributesMapper attrMapper = new RecordMapper();
assert attrMapper;
List s = ldapTemplate.search(
query().
where("sAMAccountName").is(username),
attrMapper
);
if (s == null) {
System.err.println("s is null");
}
return s?:[];
}
/** Try to fetch a record and get a modify context for it */
public runTest(String username) {
println "In ActiveDirectoryDNSample.runText($username)"
assert ldapTemplate;
def records = getByUsername(username);
println "Retrieved ${records?.size()} records";
records.each {println " $it"}
println "Now try to get the context for the records"
records.each {
person ->
println " getting context for $person";
def context = person.getContext();
println " context=$context"
}
}
public ActiveDirectoryDNSample(LdapTemplate ldapTemplate ) {
this.ldapTemplate = ldapTemplate;
}
}
In ActiveDirectoryDNSample.runText(testuser)
Retrieved 1 records
testuser <CN=Test User,CN=Users,DC=jccadmin,DC=sunyjcc,DC=edu>
Now try to get the context for the records
getting context for testuser <CN=Test User,CN=Users,DC=jccadmin,DC=sunyjcc,DC=edu>
in getContext()
...dn=CN=Test User,CN=Users,DC=jccadmin,DC=sunyjcc,DC=edu
and then it dies with a javax.naming.NameNotFoundException with the following data.
[LDAP: error code 32 - 0000208D: NameErr: DSID-03100238, problem 2001 (NO_OBJECT), data 0, best match of:
'CN=Users,DC=jccadmin,DC=sunyjcc,DC=edu'
\0]
Thanks for any help you can give me.
It turns out that there was, indeed, a better way. Instead of using an org.springframework.ldap.core.AttributesMapper in the search, you use org.springframework.ldap.core.ContextMapper.
In my example, I added a field to the Person class, which will hold a reference to the context.
DirContextOperations context;
Then I created a new class extending org.springframework.ldap.core.support.AbstractContextMapper.
class PersonContextMapper extends AbstractContextMapper {
#Override
protected Object doMapFromContext(DirContextOperations ctx) {
AttributesMapper attrMapper = new RecordMapper();
Person p = attrMapper.mapFromAttributes(ctx.attributes);
p.context = ctx;
return p;
}
}
When I passed it to the ldapTemplate.search method in the place of the AttributeMapper, I was able to use the context to update the Active Directory.
I am trying to customize the code of the spring oauth authorization server.
for now I have just copied the framework authorizationEndpoint code and placed it in another class. I just changed the address mapping to /custom/oauth/authorize. I have also added #Controller before the class declaration otherwise this code will not be used at all:
#Controller
//#Order(Ordered.HIGHEST_PRECEDENCE)
#SessionAttributes("authorizationRequest")
public class AuthorizationEndpointCustom extends AuthorizationEndpoint {
#Autowired
private AuthenticationManager authenticationManager;
private AuthorizationCodeServices authorizationCodeServices = new InMemoryAuthorizationCodeServices();
private RedirectResolver redirectResolver = new DefaultRedirectResolver();
private UserApprovalHandler userApprovalHandler = new DefaultUserApprovalHandler();
private SessionAttributeStore sessionAttributeStore = new DefaultSessionAttributeStore();
private OAuth2RequestValidator oauth2RequestValidator = new DefaultOAuth2RequestValidator();
private String userApprovalPage = "forward:/oauth/confirm_access";
private String errorPage = "forward:/oauth/error";
private Object implicitLock = new Object();
public void setSessionAttributeStore(SessionAttributeStore sessionAttributeStore) {
this.sessionAttributeStore = sessionAttributeStore;
}
public void setErrorPage(String errorPage) {
this.errorPage = errorPage;
}
#RequestMapping(value = "/oauth/authorize")
public ModelAndView authorize(Map<String, Object> model, #RequestParam Map<String, String> parameters,
SessionStatus sessionStatus, Principal principal) {
System.out.println("\n\ninside custom authorization endpoint");
// Pull out the authorization request first, using the OAuth2RequestFactory. All further logic should
// query off of the authorization request instead of referring back to the parameters map. The contents of the
// parameters map will be stored without change in the AuthorizationRequest object once it is created.
AuthorizationRequest authorizationRequest = getOAuth2RequestFactory().createAuthorizationRequest(parameters);
Set<String> responseTypes = authorizationRequest.getResponseTypes();
if (!responseTypes.contains("token") && !responseTypes.contains("code")) {
throw new UnsupportedResponseTypeException("Unsupported response types: " + responseTypes);
}
if (authorizationRequest.getClientId() == null) {
throw new InvalidClientException("A client id must be provided");
}
try {
if (!(principal instanceof Authentication) || !((Authentication) principal).isAuthenticated()) {
throw new InsufficientAuthenticationException(
"User must be authenticated with Spring Security before authorization can be completed.");
}
ClientDetails client = getClientDetailsService().loadClientByClientId(authorizationRequest.getClientId());
// The resolved redirect URI is either the redirect_uri from the parameters or the one from
// clientDetails. Either way we need to store it on the AuthorizationRequest.
String redirectUriParameter = authorizationRequest.getRequestParameters().get(OAuth2Utils.REDIRECT_URI);
String resolvedRedirect = redirectResolver.resolveRedirect(redirectUriParameter, client);
if (!StringUtils.hasText(resolvedRedirect)) {
throw new RedirectMismatchException(
"A redirectUri must be either supplied or preconfigured in the ClientDetails");
}
authorizationRequest.setRedirectUri(resolvedRedirect);
// We intentionally only validate the parameters requested by the client (ignoring any data that may have
// been added to the request by the manager).
oauth2RequestValidator.validateScope(authorizationRequest, client);
// Some systems may allow for approval decisions to be remembered or approved by default. Check for
// such logic here, and set the approved flag on the authorization request accordingly.
authorizationRequest = userApprovalHandler.checkForPreApproval(authorizationRequest,
(Authentication) principal);
// TODO: is this call necessary?
boolean approved = userApprovalHandler.isApproved(authorizationRequest, (Authentication) principal);
authorizationRequest.setApproved(approved);
// Validation is all done, so we can check for auto approval...
if (authorizationRequest.isApproved()) {
if (responseTypes.contains("token")) {
return getImplicitGrantResponse(authorizationRequest);
}
if (responseTypes.contains("code")) {
return new ModelAndView(getAuthorizationCodeResponse(authorizationRequest,
(Authentication) principal));
}
}
// Place auth request into the model so that it is stored in the session
// for approveOrDeny to use. That way we make sure that auth request comes from the session,
// so any auth request parameters passed to approveOrDeny will be ignored and retrieved from the session.
model.put("authorizationRequest", authorizationRequest);
return getUserApprovalPageResponse(model, authorizationRequest, (Authentication) principal);
}
catch (RuntimeException e) {
sessionStatus.setComplete();
throw e;
}
}
private OAuth2AccessToken getAccessTokenForImplicitGrant(TokenRequest tokenRequest,
OAuth2Request storedOAuth2Request) {
OAuth2AccessToken accessToken = null;
// These 1 method calls have to be atomic, otherwise the ImplicitGrantService can have a race condition where
// one thread removes the token request before another has a chance to redeem it.
synchronized (this.implicitLock) {
accessToken = getTokenGranter().grant("implicit",
new ImplicitTokenRequest(tokenRequest, storedOAuth2Request));
}
return accessToken;
}
.
.
.
I have also instructed the framework to change the mappring from /oauth/authorize to /custom/oauth/authorize:
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager).tokenStore(tokenStore())
.accessTokenConverter(tokenEnhancer()).pathMapping("/oauth/authorize", "/custom/authorize/");
}
but when I run the code I encounter the following error:
Description:
Field tokenGranter in com.example.demo.controller.AuthorizationEndpointCustom required a bean of type 'org.springframework.security.oauth2.provider.TokenGranter' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'org.springframework.security.oauth2.provider.TokenGranter' in your configuration.
the parent class of AuthorizationEndpoint (AbstractEndpoint) declares tokenGranter but it is not instantiated. there is no #autowired for this and other attributes of this class. who does genereate and inject these variable into this class?
how can I get hold of tokenGranter obj and inject it?
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 org.springframework.security.oauth2.provider.endpoint;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.oauth2.provider.OAuth2RequestFactory;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.TokenGranter;
import org.springframework.security.oauth2.provider.error.DefaultWebResponseExceptionTranslator;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory;
import org.springframework.util.Assert;
/**
* #author Dave Syer
*
*/
public class AbstractEndpoint implements InitializingBean {
protected final Log logger = LogFactory.getLog(getClass());
private WebResponseExceptionTranslator providerExceptionHandler = new DefaultWebResponseExceptionTranslator();
private TokenGranter tokenGranter;
private ClientDetailsService clientDetailsService;
private OAuth2RequestFactory oAuth2RequestFactory;
private OAuth2RequestFactory defaultOAuth2RequestFactory;
public void afterPropertiesSet() throws Exception {
Assert.state(tokenGranter != null, "TokenGranter must be provided");
Assert.state(clientDetailsService != null, "ClientDetailsService must be provided");
defaultOAuth2RequestFactory = new DefaultOAuth2RequestFactory(getClientDetailsService());
if (oAuth2RequestFactory == null) {
oAuth2RequestFactory = defaultOAuth2RequestFactory;
}
}
public void setProviderExceptionHandler(WebResponseExceptionTranslator providerExceptionHandler) {
this.providerExceptionHandler = providerExceptionHandler;
}
public void setTokenGranter(TokenGranter tokenGranter) {
this.tokenGranter = tokenGranter;
}
protected TokenGranter getTokenGranter() {
return tokenGranter;
}
protected WebResponseExceptionTranslator getExceptionTranslator() {
return providerExceptionHandler;
}
protected OAuth2RequestFactory getOAuth2RequestFactory() {
return oAuth2RequestFactory;
}
protected OAuth2RequestFactory getDefaultOAuth2RequestFactory() {
return defaultOAuth2RequestFactory;
}
public void setOAuth2RequestFactory(OAuth2RequestFactory oAuth2RequestFactory) {
this.oAuth2RequestFactory = oAuth2RequestFactory;
}
protected ClientDetailsService getClientDetailsService() {
return clientDetailsService;
}
public void setClientDetailsService(ClientDetailsService clientDetailsService) {
this.clientDetailsService = clientDetailsService;
}
}
I am answering my own question.
I took a good look at the framework code and I found out that AuthorizationServerEndpointsConfiguration class creates an object of type AuthorizationEndpoint and populates it's attributes and then return this object as a bean.
I managed to solve above mentioned problem with TokenGranter by creating a bean of my new AuthorizationEndpointCustom the same way AuthorizationServerEndpointsConfiguration does. this is the code to do so:
#Autowired
private ClientDetailsService clientDetailsService;
#Autowired
AuthorizationServerEndpointsConfiguration asec;
#Bean
#Order(value = Ordered.HIGHEST_PRECEDENCE)
#Primary
public AuthorizationEndpoint authorizationEndpoint () throws Exception{
AuthorizationEndpointCustom authorizationEndpoint = new AuthorizationEndpointCustom();
FrameworkEndpointHandlerMapping mapping = asec.getEndpointsConfigurer().getFrameworkEndpointHandlerMapping();
authorizationEndpoint.setUserApprovalPage(extractPath(mapping, "/oauth/confirm_access"));
authorizationEndpoint.setProviderExceptionHandler(asec.getEndpointsConfigurer().getExceptionTranslator());
authorizationEndpoint.setErrorPage(extractPath(mapping, "/oauth/error"));
authorizationEndpoint.setTokenGranter(asec.getEndpointsConfigurer().getTokenGranter());
authorizationEndpoint.setClientDetailsService(clientDetailsService);
authorizationEndpoint.setAuthorizationCodeServices(asec.getEndpointsConfigurer().getAuthorizationCodeServices());
authorizationEndpoint.setOAuth2RequestFactory(asec.getEndpointsConfigurer().getOAuth2RequestFactory());
authorizationEndpoint.setOAuth2RequestValidator(asec.getEndpointsConfigurer().getOAuth2RequestValidator());
authorizationEndpoint.setUserApprovalHandler(asec.getEndpointsConfigurer().getUserApprovalHandler());
return authorizationEndpoint;
}
private String extractPath(FrameworkEndpointHandlerMapping mapping, String page) {
String path = mapping.getPath(page);
if (path.contains(":")) {
return path;
}
return "forward:" + path;
}
but this did not result in what I hoped to. the new bean does not replace the bean from framework code. this situation with overriding beans led to another question:
how replace framework beans
buttom line, this is not the way to override the framework endpoints. you can simply create a controller with mappings for these endpoints (e.g /oauth/authorize or /oauth/token). automatically these mappings will get precedence over framework endpoints. for more info refer to spring doc
I have a Spring Boot application that uses LDAP to authenticate the users. For the users, I am mapping the attributes from AD and populating the values like the user's first name, last name, department, email, telephone, and also the image. However, I am unable to get the employee number from the attributes.
When I check the attributes using the tool Active Directory explorer, I am able to see 88 attributes per entry. However, when I print every attribute from the context using this code,
#Bean
public UserDetailsContextMapper userDetailsContextMapper() {
return new LdapUserDetailsMapper() {
#Override
public UserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<? extends GrantedAuthority> authorities) {
String email = ctx.getStringAttribute("mail");
String department = ctx.getStringAttribute("department");
String empNumber = ctx.getStringAttribute("employeeNumber");
System.out.println(empNumber); // this prints null
System.out.println(ctx.attributeExists("employeeNumber")); // this prints false
byte[] value= (byte[])ctx.getObjectAttribute("thumbNailPhoto");
BASE64Encoder base64Encoder = new BASE64Encoder();
StringBuilder imageString = new StringBuilder();
imageString.append("data:image/jpg;base64,");
imageString.append(base64Encoder.encode(value));
String image = imageString.toString();
Attributes attributes = ctx.getAttributes();
NamingEnumeration<? extends Attribute> namingEnumeration = attributes.getAll();
try {
while(namingEnumeration.hasMore()){
/*this loop prints 75 attributes but employeeNumber attribute is missing along with some other attributes*/
Attribute attribute = namingEnumeration.next();
System.out.println(attribute);
}
} catch (NamingException e) {
e.printStackTrace();
}
CustomUserDetails userDetails = (CustomUserDetails)userService.loadUserByUsername(username);
userDetails.setImage(image);
userDetails.setEmail(email);
userDetails.setDepartment(department);
return userDetails;
}
};
}
only 75 attributes are printed. Why is it that some of the attributes are not retrieved? how can i access those attributes?
I think you need to expand array elements like memberof.
Try this.. it may help.
Attribute attribute = namingEnumeration.next();
System.out.println(attribute);
System.out.println(attribute.size());
if size is greater than one.. expand it again
I have implemented Spring security in a Spring MVC web application.
For the authentication purpose I am using LDAP and for authorization I am calling a third party Web Service that provides me All the authorizations and also a Session Id.
Once user log out or session timeout, I need to call the third party web service again with the same session Id for invalidation of session.
I have created a Log out Listener that listen to SessionDestroyedEvent like this
public class LogoutListener implements ApplicationListener<SessionDestroyedEvent>{
private SecurityServiceHandler securityServiceHandler;
#Override
public void onApplicationEvent(SessionDestroyedEvent event) {
SecurityContext securityContext = event.getSecurityContext();
UserDetails ud=null;
if(securityContext!=null){
ud = (UserDetails) securityContext.getAuthentication().getPrincipal();
if(securityServiceHandler==null){
securityServiceHandler = new SecurityServiceHandler();
}
//String sessionId = securityServiceHandler.getSessionId();
String sessionId = VirgoSessionManager.getSessionId();
System.out.println(ud.getUsername());
System.out.println(VirgoSessionManager.getSessionId());
securityServiceHandler.invalidateSession(ud.getUsername(),sessionId);
//reset the sessionId
securityServiceHandler.setSessionId(null);
}
}
I have used ThreadLocal in the VirgoSessionManager Class like follow
public class VirgoSessionManager {
private static ThreadLocal<String> sessionId = new ThreadLocal<String>();
public static String getSessionId(){
return sessionId.get();
}
public static void setSessionId(String sId) {
sessionId.set(sId);
}
public static void remove() {
sessionId.remove();
}
}
My problem is the that The VirgoSessionManager is not returning the session I have set during the Third party Session creation call after successful session cration even though I have implemented thread Local.
Any help will be appreciated.
Thank you!
you can have completely different thread serving your log out functionality which results in not having any value in ThreadLocal variable. For example tomcat uses thread pools so you need to be careful here. Try to log it/debug using Thread.currentThread().getName() and Thread.currentThread().getId() in getSessionId() and a place you set this value
I fixed the issue with the separate thread calling the Logout/Session time out.
I created a new customized User class and extended the Original spring "org.springframework.security.core.userdetails.User" class. I added new field "sessionId" to my customized user class.
So whenever I get the logged user details from Spring SecurityContext during logout/timeout, I will always have that sessionId and use to call invalidateSession method.
My customized user class looks like this.
package com.wvo.custom.security;
import java.util.Collection;
import java.util.List;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
public class CustomUser extends User {
private String virgoSessionId ;
/**
*
*/
private static final long serialVersionUID = 1L;
public CustomUser(String username, String password,boolean enabled, boolean accountNonExpired, boolean accountNonLocked, boolean credentialsNonExpired,
Collection<? extends GrantedAuthority> authorities) {
super(username, password,enabled, accountNonExpired, accountNonLocked, credentialsNonExpired, authorities);
}
public String getVirgoSessionId() {
return virgoSessionId;
}
public void setVirgoSessionId(String virgoSessionId) {
this.virgoSessionId = virgoSessionId;
}
}
Thank you !
In my previous question i was working on adding roles to users logging from ldap. hopefully ive managed to register custom AuthoritiesPopulator for ldap. But now i would like to add some more functionallity to application and for that i need some more information about users than login-name.
Following this guide:
http://grails-plugins.github.io/grails-spring-security-ldap/docs/manual.106/guide/2.%20Usage.html
Im guessing i have to implement my own ldap details context mapper, and i did as shown below:
class CustomUserDetailsContextMapper implements UserDetailsContextMapper {
#Override
public UserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<? extends GrantedAuthority> authorities) {
// FETCHING DATA and ADDING ROLE
return new CustomUserDetails(trueUsername, null, true, true, true, true, list, email)
}
#Override
public void mapUserToContext(UserDetails arg0, DirContextAdapter arg1) {
throw new IllegalStateException("Only retrieving data from AD is currently supported")
}
}
And adding mapping in resource.config:
ldapUserDetailsMapper(amelinium1.grails.CustomUserDetailsContextMapper)
But it doesn't seem to work. Application seem to use GormUserDetailsService to return User not the Context. Am i missing something here ?
Would appreciate any help!