Use JAAS for LDAP Password with Spring Security

I have a Java EE web application that uses LDAP authentication. I use Spring Security to connect to my LDAP with the following code:

<bean id="ldapContextSource" class="com.myapp.security.authentication.MySecurityContextSource"> <constructor-arg index="0" value="${ldap.url}" /> <constructor-arg index="1" ref="userConnexion" /> </bean> <security:authentication-manager alias="authenticationManager"> <security:authentication-provider ref="ldapAuthProvider" /> </security:authentication-manager> <bean id="userConnexion" class="com.myapp.util.security.WebsphereCredentials"> <constructor-arg value="${ldap.authJndiAlias}" /> </bean> <bean id="ldapAuthProvider" class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider"> <constructor-arg> <bean class="org.springframework.security.ldap.authentication.BindAuthenticator"> <constructor-arg ref="ldapContextSource" /> <property name="userSearch" ref="userSearch" /> </bean> </constructor-arg> <constructor-arg> <bean class="com.myapp.security.authentication.MyAuthoritiesPopulator" > <property name="userService" ref="userService" /> </bean> </constructor-arg> <property name="userDetailsContextMapper" ref="myUserDetailsContextMapper"/> <property name="hideUserNotFoundExceptions" value="false" /> </bean> 

In fact, my WebsphereCredentials bean uses the WebSphere WSMappingCallbackHandlerFactory private class, as in this answer: How to access the authentication alias from EJB deployed in Websphere 6.1

We can see this in the official websphere documentation: http://pic.dhe.ibm.com/infocenter/wasinfo/v6r1/index.jsp?topic=%2Fcom.ibm.websphere.express.doc%2Finfo%2Fexp%2Fae% 2Frsec_pluginj2c.html

But I do not want this because:

  • I think my application can access all JAAS inputs in my WebSphere instance (not sure).
  • This class is defined in the IBM HUGE client library com.ibm.ws.admin.client-7.0.0.jar (42 Mo) => slower than compilation not present in my corporate nexus
  • It is not portable, not standard

For information, I define the WebsphereCredentials constructor as follows:

 Map<String, String> map = new HashMap<String, String>(); map.put(Constants.MAPPING_ALIAS, this.jndiAlias); Subject subject; try { CallbackHandler callbackHandler = WSMappingCallbackHandlerFactory.getInstance().getCallbackHandler(map, null); LoginContext lc = new LoginContext("DefaultPrincipalMapping", callbackHandler); lc.login(); subject = lc.getSubject(); } catch (NotImplementedException e) { throw new EfritTechnicalException(EfritTechnicalExceptionEnum.LOGIN_CREDENTIAL_PROBLEM, e); } catch (LoginException e) { throw new EfritTechnicalException(EfritTechnicalExceptionEnum.LOGIN_CREDENTIAL_PROBLEM, e); } PasswordCredential cred = (PasswordCredential) subject.getPrivateCredentials().toArray()[0]; this.user = cred.getUserName(); this.password = String.valueOf(cred.getPassword()); 

Is there a way to use only Spring Security and remove this dependency?

I have no idea how to combine http://static.springsource.org/spring-security/site/docs/3.1.x/reference/jaas.html and http://static.springsource.org/spring-security/site /docs/3.1.x/reference/ldap.html .

Perhaps I should completely change my approach and use a different way?

+4
authentication spring-security websphere jaas ldap
source share
1 answer

I assume your goal is to simply use the username / password that you configure in WebSphere to connect to the LDAP directory? If so, you are not trying to combine LDAP and JAAS authentication. JAAS support is really designed to use the JAAS LoginModule to authenticate the user instead of using LDAP-based authentication.

If you want to get a username and password regardless of compilation time in WebSphere, you have several options.

Elimination of compilation time and runtime dependencies on WAS

One option is to set the password differently. It can be as simple as using the password directly in the configuration file, as shown in the Spring Security LDAP documentation :

 <bean id="ldapContextSource" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource"> <constructor-arg value="ldap://monkeymachine:389/dc=springframework,dc=org"/> <property name="userDn" value="cn=manager,dc=springframework,dc=org"/> <property name="password" value="password"/> </bean> 

You can also configure the username password in JNDI. Another alternative is to use a .properties file with Property. If you want the password to be protected, you probably want to encrypt the password using something like Jasypt .

Eliminate compile-time dependencies and configure using WAS

If you need or need WebSphere J2C support for storing credentials, you can do this by introducing an instance of CallbackHandler . For example, your WebsphereCredentials bean might WebsphereCredentials something like this:

 try { LoginContext lc = new LoginContext("DefaultPrincipalMapping", this.callbackHandler); lc.login(); subject = lc.getSubject(); } catch (NotImplementedException e) { throw new EfritTechnicalException(EfritTechnicalExceptionEnum.LOGIN_CREDENTIAL_PROBLEM, e); } catch (LoginException e) { throw new EfritTechnicalException(EfritTechnicalExceptionEnum.LOGIN_CREDENTIAL_PROBLEM, e); } PasswordCredential cred = (PasswordCredential) subject.getPrivateCredentials().toArray()[0]; this.user = cred.getUserName(); this.password = String.valueOf(cred.getPassword()); 

Your configuration will look something like this:

 <bean id="userConnexion" class="com.myapp.util.security.WebsphereCredentials"> <constructor-arg ref="wasCallbackHandler"/> </bean> <bean id="wasCallbackHandler" factory-bean="wasCallbackFactory" factory-method="getCallbackHandler"> <constructor-arg> <map> <entry value="${ldap.authJndiAlias}"> <key> <util:constant static-field="com.ibm.wsspi.security.auth.callback.Constants.MAPPING_ALIAS"/> </key> </entry> </map> </constructor-arg> <constructor-arg> <null /> </constructor-arg> </bean> <bean id="wasCallbackFactory" class="com.ibm.wsspi.security.auth.callback.WSMappingCallbackHandlerFactory" factory-method="getInstance" /> 

Renouncement

CallbackHandler instances are not thread safe and generally should not be used more than once. Thus, it can be a little risky introducing CallbackHandler instances as member variables. You can program a test to ensure that the CallbackHandler used only once.

Hybrid approach

You can use a hybrid approach that always removes the compile-time dependency and allows you to remove the run-time dependency in cases where you cannot work in WebSphere. This can be done by combining the two sentences and using the Spring bean Profile Definitions to distinguish between working in WebSphere and a machine other than WebSphere.

+5
source share

All Articles