blob: bb1268ce5c43a940ee657e347a0731ccd71211f7 [file] [log] [blame]
/*
* Copyright 2005-2008 Jeremy Haile
*
* 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.jsecurity.realm.ldap;
import org.jsecurity.authc.Account;
import org.jsecurity.authc.AuthenticationException;
import org.jsecurity.authc.AuthenticationToken;
import org.jsecurity.authz.AuthorizingAccount;
import org.jsecurity.realm.AuthorizingRealm;
import org.jsecurity.realm.Realm;
import org.jsecurity.subject.PrincipalCollection;
import org.jsecurity.util.Initializable;
import javax.naming.NamingException;
/**
* <p>A {@link Realm} that authenticates with an LDAP
* server to build the Subject for a user. This implementation only returns roles for a
* particular user, and not permissions - but it can be subclassed to build a permission
* list as well.</p>
*
* <p>Implementations would need to implement the
* {@link #queryForLdapAccount(org.jsecurity.authc.AuthenticationToken,LdapContextFactory) queryForLdapAccount} and
* {@link #queryForLdapAccount(PrincipalCollection,LdapContextFactory) queryForLdapAccount} abstract methods.</p>
*
* <p>By default, this implementation will create an instance of {@link DefaultLdapContextFactory} to use for
* creating LDAP connections using the principalSuffix, searchBase, url, systemUsername, and systemPassword properties
* specified on the realm. The remaining settings use the defaults of {@link DefaultLdapContextFactory}, which are usually
* sufficient. If more customized connections are needed, you should inject a custom {@link LdapContextFactory}, which
* will cause these properties specified on the realm to be ignored.</p>
*
* @author Jeremy Haile
* @author Les Hazlewood
* @see #queryForLdapAccount(org.jsecurity.authc.AuthenticationToken, LdapContextFactory)
* @see #queryForLdapAccount(PrincipalCollection, LdapContextFactory)
* @since 0.1
*/
public abstract class AbstractLdapRealm extends AuthorizingRealm implements Initializable {
/*--------------------------------------------
| C O N S T A N T S |
============================================*/
/*--------------------------------------------
| I N S T A N C E V A R I A B L E S |
============================================*/
protected String principalSuffix = null;
protected String searchBase = null;
protected String url = null;
protected String systemUsername = null;
protected String systemPassword = null;
private LdapContextFactory ldapContextFactory = null;
/*--------------------------------------------
| C O N S T R U C T O R S |
============================================*/
/*--------------------------------------------
| A C C E S S O R S / M O D I F I E R S |
============================================*/
/*--------------------------------------------
| M E T H O D S |
============================================*/
/**
* Used when initializing the default {@link LdapContextFactory}. This property is ignored if a custom
* <tt>LdapContextFactory</tt> is specified.
*
* @param principalSuffix the suffix.
* @see DefaultLdapContextFactory#setPrincipalSuffix(String)
*/
public void setPrincipalSuffix( String principalSuffix ) {
this.principalSuffix = principalSuffix;
}
/**
* Used when initializing the default {@link LdapContextFactory}. This property is ignored if a custom
* <tt>LdapContextFactory</tt> is specified.
*
* @param searchBase the search base.
* @see DefaultLdapContextFactory#setSearchBase(String)
*/
public void setSearchBase( String searchBase ) {
this.searchBase = searchBase;
}
/**
* Used when initializing the default {@link LdapContextFactory}. This property is ignored if a custom
* <tt>LdapContextFactory</tt> is specified.
*
* @param url the LDAP url.
* @see DefaultLdapContextFactory#setUrl(String)
*/
public void setUrl( String url ) {
this.url = url;
}
/**
* Used when initializing the default {@link LdapContextFactory}. This property is ignored if a custom
* <tt>LdapContextFactory</tt> is specified.
*
* @param systemUsername the username to use when logging into the LDAP server for authorization.
* @see DefaultLdapContextFactory#setSystemUsername(String)
*/
public void setSystemUsername( String systemUsername ) {
this.systemUsername = systemUsername;
}
/**
* Used when initializing the default {@link LdapContextFactory}. This property is ignored if a custom
* <tt>LdapContextFactory</tt> is specified.
*
* @param systemPassword the password to use when logging into the LDAP server for authorization.
* @see DefaultLdapContextFactory#setSystemPassword(String)
*/
public void setSystemPassword( String systemPassword ) {
this.systemPassword = systemPassword;
}
/**
* Configures the {@link LdapContextFactory} implementation that is used to create LDAP connections for
* authentication and authorization. If this is set, the {@link LdapContextFactory} provided will be used.
* Otherwise, a {@link DefaultLdapContextFactory} instance will be created based on the properties specified
* in this realm.
* @param ldapContextFactory the factory to use - if not specified, a default factory will be created automatically.
*/
public void setLdapContextFactory(LdapContextFactory ldapContextFactory) {
this.ldapContextFactory = ldapContextFactory;
}
/*--------------------------------------------
| M E T H O D S |
============================================*/
protected void afterAccountCacheSet() {
if( ldapContextFactory == null ) {
if( log.isDebugEnabled() ) {
log.debug( "No LdapContextFactory is specified, so a default instance is being created." );
}
DefaultLdapContextFactory defaultFactory = new DefaultLdapContextFactory();
defaultFactory.setPrincipalSuffix( this.principalSuffix );
defaultFactory.setSearchBase( this.searchBase );
defaultFactory.setUrl( this.url );
defaultFactory.setSystemUsername( this.systemUsername );
defaultFactory.setSystemPassword( this.systemPassword );
ldapContextFactory = defaultFactory;
}
}
protected Account doGetAccount( AuthenticationToken token ) throws AuthenticationException {
Account account = null;
try {
account = queryForLdapAccount( token, this.ldapContextFactory );
} catch ( NamingException e ) {
if ( log.isErrorEnabled() ) {
final String message = "LDAP naming error while attempting to authenticate user.";
log.error( message, e );
}
}
return account;
}
protected AuthorizingAccount doGetAccount( PrincipalCollection principals ) {
AuthorizingAccount authorizingAccount = null;
try {
authorizingAccount = queryForLdapAccount( principals, this.ldapContextFactory );
} catch( NamingException e ) {
if ( log.isErrorEnabled() ) {
final String message = "LDAP naming error while attempting to retrieve authorization for user [" + principals + "].";
log.error( message, e );
}
}
return authorizingAccount;
}
/**
* <p>Abstract method that should be implemented by subclasses to builds an
* {@link org.jsecurity.authc.Account} object by querying the LDAP context for the
* specified username.</p>
*
* @param token the authentication token given during authentication.
* @param ldapContextFactory factory used to retrieve LDAP connections.
* @return an {@link org.jsecurity.authz.SimpleAuthorizingAccount} instance containing information retrieved from the LDAP server.
* @throws NamingException if any LDAP errors occur during the search.
*/
protected abstract Account queryForLdapAccount( AuthenticationToken token, LdapContextFactory ldapContextFactory) throws NamingException;
/**
* <p>Abstract method that should be implemented by subclasses to builds an
* {@link org.jsecurity.authz.SimpleAuthorizingAccount} object by querying the LDAP context for the
* specified principal.</p>
*
* @param principal the principal of the Subject whose Account should be queried from the LDAP server.
* @param ldapContextFactory factory used to retrieve LDAP connections.
* @return an {@link org.jsecurity.authz.SimpleAuthorizingAccount} instance containing information retrieved from the LDAP server.
* @throws NamingException if any LDAP errors occur during the search.
*/
protected abstract AuthorizingAccount queryForLdapAccount( PrincipalCollection principal, LdapContextFactory ldapContextFactory) throws NamingException;
}