Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
// ========================================================================
// Copyright (c) 2007-2009 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.plus.jaas.spi;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginException;
import org.eclipse.jetty.http.security.Credential;
import org.eclipse.jetty.plus.jaas.callback.ObjectCallback;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/**
* A LdapLoginModule for use with JAAS setups
*
* The jvm should be started with the following parameter:
*
*
*
*
*
*/
public class LdapLoginModule extends AbstractLoginModule
{
private static final Logger LOG = Log.getLogger(LdapLoginModule.class);
/**
* hostname of the ldap server
*/
private String _hostname;
/**
* port of the ldap server
*/
private int _port;
/**
* Context.SECURITY_AUTHENTICATION
*/
private String _authenticationMethod;
/**
* Context.INITIAL_CONTEXT_FACTORY
*/
private String _contextFactory;
/**
* root DN used to connect to
*/
private String _bindDn;
/**
* password used to connect to the root ldap context
*/
private String _bindPassword;
/**
* object class of a user
*/
private String _userObjectClass = "inetOrgPerson";
/**
* attribute that the principal is located
*/
private String _userRdnAttribute = "uid";
/**
* attribute that the principal is located
*/
private String _userIdAttribute = "cn";
/**
* name of the attribute that a users password is stored under
*
* NOTE: not always accessible, see force binding login
*/
private String _userPasswordAttribute = "userPassword";
/**
* base DN where users are to be searched from
*/
private String _userBaseDn;
/**
* base DN where role membership is to be searched from
*/
private String _roleBaseDn;
/**
* object class of roles
*/
private String _roleObjectClass = "groupOfUniqueNames";
/**
* name of the attribute that a username would be under a role class
*/
private String _roleMemberAttribute = "uniqueMember";
/**
* the name of the attribute that a role would be stored under
*/
private String _roleNameAttribute = "roleName";
private boolean _debug;
/**
* if the getUserInfo can pull a password off of the user then
* password comparison is an option for authn, to force binding
* login checks, set this to true
*/
private boolean _forceBindingLogin = false;
/**
* When true changes the protocol to ldaps
*/
private boolean _useLdaps = false;
private DirContext _rootContext;
/**
* get the available information about the user
*
* for this LoginModule, the credential can be null which will result in a
* binding ldap authentication scenario
*
* roles are also an optional concept if required
*
* @param username
* @return the userinfo for the username
* @throws Exception
*/
public UserInfo getUserInfo(String username) throws Exception
{
String pwdCredential = getUserCredentials(username);
if (pwdCredential == null)
{
return null;
}
pwdCredential = convertCredentialLdapToJetty(pwdCredential);
Credential credential = Credential.getCredential(pwdCredential);
List roles = getUserRoles(_rootContext, username);
return new UserInfo(username, credential, roles);
}
protected String doRFC2254Encoding(String inputString)
{
StringBuffer buf = new StringBuffer(inputString.length());
for (int i = 0; i < inputString.length(); i++)
{
char c = inputString.charAt(i);
switch (c)
{
case '\\':
buf.append("\\5c");
break;
case '*':
buf.append("\\2a");
break;
case '(':
buf.append("\\28");
break;
case ')':
buf.append("\\29");
break;
case '\0':
buf.append("\\00");
break;
default:
buf.append(c);
break;
}
}
return buf.toString();
}
/**
* attempts to get the users credentials from the users context
*
* NOTE: this is not an user authenticated operation
*
* @param username
* @return
* @throws LoginException
*/
private String getUserCredentials(String username) throws LoginException
{
String ldapCredential = null;
SearchControls ctls = new SearchControls();
ctls.setCountLimit(1);
ctls.setDerefLinkFlag(true);
ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
String filter = "(&(objectClass={0})({1}={2}))";
LOG.debug("Searching for users with filter: \'" + filter + "\'" + " from base dn: " + _userBaseDn);
try
{
Object[] filterArguments = {_userObjectClass, _userIdAttribute, username};
NamingEnumeration results = _rootContext.search(_userBaseDn, filter, filterArguments, ctls);
LOG.debug("Found user?: " + results.hasMoreElements());
if (!results.hasMoreElements())
{
throw new LoginException("User not found.");
}
SearchResult result = findUser(username);
Attributes attributes = result.getAttributes();
Attribute attribute = attributes.get(_userPasswordAttribute);
if (attribute != null)
{
try
{
byte[] value = (byte[]) attribute.get();
ldapCredential = new String(value);
}
catch (NamingException e)
{
LOG.debug("no password available under attribute: " + _userPasswordAttribute);
}
}
}
catch (NamingException e)
{
throw new LoginException("Root context binding failure.");
}
LOG.debug("user cred is: " + ldapCredential);
return ldapCredential;
}
/**
* attempts to get the users roles from the root context
*
* NOTE: this is not an user authenticated operation
*
* @param dirContext
* @param username
* @return
* @throws LoginException
*/
private List getUserRoles(DirContext dirContext, String username) throws LoginException, NamingException
{
String userDn = _userRdnAttribute + "=" + username + "," + _userBaseDn;
return getUserRolesByDn(dirContext, userDn);
}
private List getUserRolesByDn(DirContext dirContext, String userDn) throws LoginException, NamingException
{
List roleList = new ArrayList();
if (dirContext == null || _roleBaseDn == null || _roleMemberAttribute == null || _roleObjectClass == null)
{
return roleList;
}
SearchControls ctls = new SearchControls();
ctls.setDerefLinkFlag(true);
ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
String filter = "(&(objectClass={0})({1}={2}))";
Object[] filterArguments = {_roleObjectClass, _roleMemberAttribute, userDn};
NamingEnumeration results = dirContext.search(_roleBaseDn, filter, filterArguments, ctls);
LOG.debug("Found user roles?: " + results.hasMoreElements());
while (results.hasMoreElements())
{
SearchResult result = (SearchResult) results.nextElement();
Attributes attributes = result.getAttributes();
if (attributes == null)
{
continue;
}
Attribute roleAttribute = attributes.get(_roleNameAttribute);
if (roleAttribute == null)
{
continue;
}
NamingEnumeration roles = roleAttribute.getAll();
while (roles.hasMore())
{
roleList.add(roles.next().toString());
}
}
return roleList;
}
/**
* since ldap uses a context bind for valid authentication checking, we override login()
*
* if credentials are not available from the users context or if we are forcing the binding check
* then we try a binding authentication check, otherwise if we have the users encoded password then
* we can try authentication via that mechanic
*
* @return true if authenticated, false otherwise
* @throws LoginException
*/
public boolean login() throws LoginException
{
try
{
if (getCallbackHandler() == null)
{
throw new LoginException("No callback handler");
}
Callback[] callbacks = configureCallbacks();
getCallbackHandler().handle(callbacks);
String webUserName = ((NameCallback) callbacks[0]).getName();
Object webCredential = ((ObjectCallback) callbacks[1]).getObject();
if (webUserName == null || webCredential == null)
{
setAuthenticated(false);
return isAuthenticated();
}
if (_forceBindingLogin)
{
return bindingLogin(webUserName, webCredential);
}
// This sets read and the credential
UserInfo userInfo = getUserInfo(webUserName);
if (userInfo == null)
{
setAuthenticated(false);
return false;
}
setCurrentUser(new JAASUserInfo(userInfo));
if (webCredential instanceof String)
{
return credentialLogin(Credential.getCredential((String) webCredential));
}
return credentialLogin(webCredential);
}
catch (UnsupportedCallbackException e)
{
throw new LoginException("Error obtaining callback information.");
}
catch (IOException e)
{
if (_debug)
{
e.printStackTrace();
}
throw new LoginException("IO Error performing login.");
}
catch (Exception e)
{
if (_debug)
{
e.printStackTrace();
}
throw new LoginException("Error obtaining user info.");
}
}
/**
* password supplied authentication check
*
* @param webCredential
* @return true if authenticated
* @throws LoginException
*/
protected boolean credentialLogin(Object webCredential) throws LoginException
{
setAuthenticated(getCurrentUser().checkCredential(webCredential));
return isAuthenticated();
}
/**
* binding authentication check
* This method of authentication works only if the user branch of the DIT (ldap tree)
* has an ACI (access control instruction) that allow the access to any user or at least
* for the user that logs in.
*
* @param username
* @param password
* @return true always
* @throws LoginException
*/
public boolean bindingLogin(String username, Object password) throws LoginException, NamingException
{
SearchResult searchResult = findUser(username);
String userDn = searchResult.getNameInNamespace();
LOG.info("Attempting authentication: " + userDn);
Hashtable