blob: 0a1d119a80a863c427fefbe8002f8e6223fa27c9 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.ki.realm.ldap;
import javax.naming.NamingException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.ki.authc.AuthenticationException;
import org.apache.ki.authc.AuthenticationInfo;
import org.apache.ki.authc.AuthenticationToken;
import org.apache.ki.authz.AuthorizationInfo;
import org.apache.ki.realm.AuthorizingRealm;
import org.apache.ki.subject.PrincipalCollection;
/**
* <p>A {@link org.apache.ki.realm.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 #queryForAuthenticationInfo(org.apache.ki.authc.AuthenticationToken ,LdapContextFactory)} and
* {@link #queryForAuthorizationInfo(org.apache.ki.subject.PrincipalCollection ,LdapContextFactory)} 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 #queryForAuthenticationInfo(org.apache.ki.authc.AuthenticationToken , LdapContextFactory)
* @see #queryForAuthorizationInfo(org.apache.ki.subject.PrincipalCollection , LdapContextFactory)
* @since 0.1
*/
public abstract class AbstractLdapRealm extends AuthorizingRealm {
//TODO - complete JavaDoc
/*--------------------------------------------
| C O N S T A N T S |
============================================*/
private static final Logger log = LoggerFactory.getLogger(AbstractLdapRealm.class);
/*--------------------------------------------
| 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 afterAuthorizationCacheSet() {
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 AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
AuthenticationInfo info = null;
try {
info = queryForAuthenticationInfo(token, this.ldapContextFactory);
} catch (javax.naming.AuthenticationException e) {
throw new AuthenticationException( "LDAP authentication failed.", e );
} catch (NamingException e) {
if (log.isErrorEnabled()) {
final String message = "LDAP naming error while attempting to authenticate user.";
log.error(message, e);
}
}
return info;
}
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
AuthorizationInfo info = null;
try {
info = queryForAuthorizationInfo(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 info;
}
/**
* <p>Abstract method that should be implemented by subclasses to builds an
* {@link AuthenticationInfo} 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 AuthenticationInfo} instance containing information retrieved from the LDAP server.
* @throws NamingException if any LDAP errors occur during the search.
*/
protected abstract AuthenticationInfo queryForAuthenticationInfo(AuthenticationToken token, LdapContextFactory ldapContextFactory) throws NamingException;
/**
* <p>Abstract method that should be implemented by subclasses to builds an
* {@link AuthorizationInfo} object by querying the LDAP context for the
* specified principal.</p>
*
* @param principal the principal of the Subject whose AuthenticationInfo should be queried from the LDAP server.
* @param ldapContextFactory factory used to retrieve LDAP connections.
* @return an {@link AuthorizationInfo} instance containing information retrieved from the LDAP server.
* @throws NamingException if any LDAP errors occur during the search.
*/
protected abstract AuthorizationInfo queryForAuthorizationInfo(PrincipalCollection principal, LdapContextFactory ldapContextFactory) throws NamingException;
}