You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tomcat.apache.org by Randy Secrist <to...@secristfamily.com> on 2002/08/20 19:46:00 UTC

JNDI Realm Help - (using iplanet)

Hello,

I am trying to get TC (4.0.4) to establish a working JNDI realm using
iplanet's directory server.  I am using FORM based login and have this
working as a JDBC realm previously.

As you can see below, I would like to keep my users and roles in
ou=warnertruck,ou=truckcenter,dc=secristfamily,dc=com.  Iplanet sets up each
user with a role nsrole, and nsroledn.  I have tried switching the values
for roleName, and roleSearch, and since iplanet stores passwords using SHA,
I even threw on a digest="SHA" in the realm tag.  I have messed with this
for months now, and have searched the web extensivly for help.  Would
someone please tell me what I need to do to get this working?

If I can actually get this working, I will be most elated!

Randy Secrist

Below are my catalina.log, and server.xml...

2002-08-20 11:32:04 JNDIRealm[WarnerTruck]: Connecting to URL
ldap://myserver.com/
2002-08-20 11:32:26 JNDIRealm[WarnerTruck]: getUserDN(RSecrist)
2002-08-20 11:32:26 JNDIRealm[WarnerTruck]:
dn=uid=RSecrist,ou=warnertruck,ou=truckcenter,dc=secristfamily,dc=com
2002-08-20 11:32:26 JNDIRealm[WarnerTruck]:   retrieving attribute
userPassword
2002-08-20 11:32:26 JNDIRealm[WarnerTruck]:   retrieving value
2002-08-20 11:32:26 JNDIRealm[WarnerTruck]:   validating credentials
2002-08-20 11:32:26 JNDIRealm[WarnerTruck]: Username RSecrist NOT
successfully authenticated

----------------------------------------------------------------------------
-----------------------------------------------------

Here is my server.xml snippet:
<Realm   className="org.apache.catalina.realm.JNDIRealm" debug="99"
connectionName="cn=DirectoryManager" connectionPassword="pleaseWork"
connectionURL="ldap://myserver.com/"
roleBase="ou=warnertruck,ou=truckcenter,dc=secristfamily,dc=com"
roleName="nsroledn"
roleSearch="(cn={0},ou=warnertruck,ou=truckcenter,dc=secristfamily,dc=com)"
roleSubtree="false" userPassword="userPassword"
userPattern="uid={0},ou=warnertruck,ou=truckcenter,dc=secristfamily,dc=com"
/>

----------------------------------------------------------------------------
-----------------------------------------------------


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: JNDI Realm Help - (using iplanet)

Posted by Tim Funk <fu...@joedog.org>.
I don't know. The reason JNDIRealm did not work was IPlanet returns the 
SHA digested password as a Base64 encoded (Mime like) string. The 
(original) tomcat code takes the passsword and converts it to a Hex 
string. Base64 string will never equal the Hex string.

I have no idea what MySQL returns. If it returns a Hex String of the 
digested password - you might be in luck.

Randy Secrist wrote:
> Thank you Tim, your response has helped greatly!  I was able to compile and
> use your implementation of IPlanetRealm to get it working!  Now I just need
> to look at the 4.1.x JNDIRealm to see if it fixes that base64 encoding
> problems.
> 
> Do yo know if that base64 problem carries over into the JDBCRealm at all?
> (For using SHA with say - mysql?)
> 
> Randy
> 
> ----- Original Message -----
> From: "Tim Funk" <fu...@joedog.org>
> To: "Tomcat Users List" <to...@jakarta.apache.org>
> Sent: Tuesday, August 20, 2002 12:04 PM
> Subject: Re: JNDI Realm Help - (using iplanet)
> 
> 
> 
>>IPlanet with SHA does not work together in 4.0.4. The password coming
>>back from iPlanet is compared incorrectly with respect to digesting the
>>user provided password.
>>
>>You have 3 alternatives:
>>1) Hack JNDIRealm (Attached is one I did and am using until upgrading to
>>4.1.X)
>>2) Use 4.1.X and bind as the user
>>3) Use JNDIRealm from the 4.1.X tree and bind as the user
>>
>>-Tim
>>
>>Randy Secrist wrote:
>>
>>>Hello,
>>>
>>>I am trying to get TC (4.0.4) to establish a working JNDI realm using
>>>iplanet's directory server.  I am using FORM based login and have this
>>>working as a JDBC realm previously.
>>>
>>>As you can see below, I would like to keep my users and roles in
>>>ou=warnertruck,ou=truckcenter,dc=secristfamily,dc=com.  Iplanet sets up
>>
> each
> 
>>>user with a role nsrole, and nsroledn.  I have tried switching the
>>
> values
> 
>>>for roleName, and roleSearch, and since iplanet stores passwords using
>>
> SHA,
> 
>>>I even threw on a digest="SHA" in the realm tag.  I have messed with
>>
> this
> 
>>>for months now, and have searched the web extensivly for help.  Would
>>>someone please tell me what I need to do to get this working?
>>>
>>>If I can actually get this working, I will be most elated!
>>>
>>>Randy Secrist
>>>
>>
> 
> 
> ----------------------------------------------------------------------------
> ----
> 
> 
> 
>>/*
>> * The Apache Software License, Version 1.1
>> *
>> * Copyright (c) 1999 The Apache Software Foundation.  All rights
>> * reserved.
>> *
>> * Redistribution and use in source and binary forms, with or without
>> * modification, are permitted provided that the following conditions
>> * are met:
>> *
>> * 1. Redistributions of source code must retain the above copyright
>> *    notice, this list of conditions and the following disclaimer.
>> *
>> * 2. Redistributions in binary form must reproduce the above copyright
>> *    notice, this list of conditions and the following disclaimer in
>> *    the documentation and/or other materials provided with the
>> *    distribution.
>> *
>> * 3. The end-user documentation included with the redistribution, if
>> *    any, must include the following acknowlegement:
>> *       "This product includes software developed by the
>> *        Apache Software Foundation (http://www.apache.org/)."
>> *    Alternately, this acknowlegement may appear in the software itself,
>> *    if and wherever such third-party acknowlegements normally appear.
>> *
>> * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
>> *    Foundation" must not be used to endorse or promote products derived
>> *    from this software without prior written permission. For written
>> *    permission, please contact apache@apache.org.
>> *
>> * 5. Products derived from this software may not be called "Apache"
>> *    nor may "Apache" appear in their names without prior written
>> *    permission of the Apache Group.
>> *
>> * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
>> * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
>> * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
>> * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
>> * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
>> * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
>> * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
>> * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
>> * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
>> * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
>> * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
>> * SUCH DAMAGE.
>> * ====================================================================
>> *
>> * This software consists of voluntary contributions made by many
>> * individuals on behalf of the Apache Software Foundation.  For more
>> * information on the Apache Software Foundation, please see
>> * <http://www.apache.org/>.
>> *
>> * [Additional notices, if required by prior licensing conditions]
>> *
>> */
>>
>>
>>package org.joedog.scrapme.ldap;
>>
>>import java.security.Principal;
>>import java.text.MessageFormat;
>>import java.util.ArrayList;
>>import java.util.Hashtable;
>>import java.util.List;
>>import javax.naming.Context;
>>import javax.naming.NameNotFoundException;
>>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 org.apache.catalina.LifecycleException;
>>import org.apache.catalina.Realm;
>>import org.apache.catalina.util.StringManager;
>>import org.apache.catalina.realm.*;
>>
>>
>>/**
>> * <h1>For temporary usage with Tomcat 4.0.4 or earlier. This
>> *     is a copy of the JNDIRealm with a few patches!
>> * </h1>
>> *
>> * <br /><br /><br />
>> * <p>Implementation of <strong>Realm</strong> that works with a directory
>> * server accessed via the Java Naming and Directory Interface (JNDI)
> 
> APIs.
> 
>> * The following constraints are imposed on the data structure in the
>> * underlying directory server:</p>
>> * <ul>
>> * <li>Each user that can be authenticated is represented by an individual
>> *     element in the top level <code>DirContext</code> that is accessed
>> *     via the <code>connectionURL</code> property.  This element has the
>> *     following characteristics:
>> *     <ul>
>> *     <li>The distinguished name (<code>dn</code>) attribute of this
> 
> element
> 
>> *         contains the username that is being presented for
> 
> authentication.
> 
>> *         </li>
>> *     <li>The distinguished name can be represented by a pattern passed
> 
> to
> 
>> *         an instance of <code>MessageFormat</code>, where the string
> 
> "{0}"
> 
>> *         in the pattern is replaced by the username being
> 
> presented.</li>
> 
>> *     <li>The element for this user contains an attribute named by the
>> *         <code>userPassword</code> property.  The value of this
> 
> attribute
> 
>> *         is retrieved for use in authentication.</li>
>> *     <li>The value of the user password attribute is either a cleartext
>> *         String, or the result of passing a cleartext String through the
>> *         <code>RealmBase.digest()</code> method (using the standard
> 
> digest
> 
>> *         support included in <code>RealmBase</code>).
>> *     <li>The user is considered to be authenticated if the presented
>> *         credentials (after being passed through
>> *         <code>RealmBase.digest()</code>) are equal to the retrieved
> 
> value
> 
>> *         for the user password attribute.</li>
>> *     </ul></li>
>> * <li>Each group of users that has been assigned a particular role is
>> *     represented by an individual element in the top level
>> *     <code>DirContext</code> that is accessed via the
>> *     <code>connectionURL</code> property.  This element has the
> 
> following
> 
>> *     characteristics:
>> *     <ul>
>> *     <li>The set of all possible groups of interest can be selected by a
>> *         search pattern configured by the <code>roleSearch</code>
>> *         property.</li>
>> *     <li>The <code>roleSearch</code> pattern optionally includes pattern
>> *         replacements "{0}" for the distinguished name, and/or "{1}" for
>> *         the username, of the authenticated user for which roles will be
>> *         retrieved.</li>
>> *     <li>The <code>roleBase</code> property can be set to the element
> 
> that
> 
>> *         is the base of the search for matching roles.  If not
> 
> specified,
> 
>> *         the entire context will be searched.</li>
>> *     <li>The <code>roleSubtree</code> property can be set to
>> *         <code>true</code> if you wish to search the entire subtree of
> 
> the
> 
>> *         directory context.  The default value of <code>false</code>
>> *         requests a search of only the current level.</li>
>> *     <li>The element includes an attribute (whose name is configured by
>> *         the <code>roleName</code> property) containing the name of the
>> *         role represented by this element.</li>
>> *     </ul></li>
>> * <li>Note that the standard <code>&lt;security-role-ref&gt;</code>
> 
> element in
> 
>> *     the web application deployment descriptor allows applications to
> 
> refer
> 
>> *     to roles programmatically by names other than those used in the
>> *     directory server itself.</li>
>> * </ul>
>> *
>> * <p><strong>TODO</strong> - Support connection pooling (including
> 
> message
> 
>> * format objects) so that <code>authenticate()</code> does not have to be
>> * synchronized.</p>
>> *
>> * <p><strong>TODO</strong> - Get rid of this class and use JNDIRealm. But
>> * JNDIRealm needs patched because IPLanet returns Base64 SHA passwords
>> * and the the current JNDIRealm doesn't handle that.
>> * </p>
>> *
>> * @author Tim Funk
>> * @version $Revision: 1.1.1.1 $ $Date: 2002/06/26 18:21:21 $
>> */
>>
>>public class IPlanetRealm extends RealmBase {
>>
>>
>>    // ----------------------------------------------------- Instance
> 
> Variables
> 
>>
>>    /**
>>     * The connection username for the server we will contact.
>>     */
>>    protected String connectionName = null;
>>
>>
>>    /**
>>     * The connection password for the server we will contact.
>>     */
>>    protected String connectionPassword = null;
>>
>>
>>    /**
>>     * The connection URL for the server we will contact.
>>     */
>>    protected String connectionURL = null;
>>
>>
>>    /**
>>     * The directory context linking us to our directory server.
>>     */
>>    protected DirContext context = null;
>>
>>
>>    /**
>>     * The JNDI context factory used to acquire our InitialContext.  By
>>     * default, assumes use of an LDAP server using the standard JNDI LDAP
>>     * provider.
>>     */
>>    protected String contextFactory = "com.sun.jndi.ldap.LdapCtxFactory";
>>
>>
>>    /**
>>     * Descriptive information about this Realm implementation.
>>     */
>>    protected static final String info =
>>        "org.apache.catalina.realm.JNDIRealm/1.0";
>>
>>
>>    /**
>>     * Descriptive information about this Realm implementation.
>>     */
>>    protected static final String name = "JNDIRealm";
>>
>>
>>    /**
>>     * The base element for role searches.
>>     */
>>    protected String roleBase = "";
>>
>>
>>    /**
>>     * The MessageFormat object associated with the current
>>     * <code>roleSearch</code>.
>>     */
>>    protected MessageFormat roleFormat = null;
>>
>>
>>    /**
>>     * The name of the attribute containing the role name.
>>     */
>>    protected String roleName[] = null;
>>
>>
>>    /**
>>     * The message format used to select roles for a user, with "{0}"
> 
> marking
> 
>>     * the spot where the distinguished name of the user goes.
>>     */
>>    protected String roleSearch = null;
>>
>>
>>    /**
>>     * Should we search the entire subtree for matching memberships?
>>     */
>>    protected boolean roleSubtree = false;
>>
>>
>>    /**
>>     * The MessageFormat object associated with the current
>>     * <code>userPattern</code>.
>>     */
>>    protected MessageFormat userFormat = null;
>>
>>
>>    /**
>>     * The attribute name used to retrieve the user password.
>>     */
>>    protected String userPassword[] = null;
>>
>>
>>    /**
>>     * The message format used to select a user, with "{0}" marking the
>>     * spot where the specified username goes.
>>     */
>>    protected String userPattern = null;
>>
>>
>>    // -------------------------------------------------------------
> 
> Properties
> 
>>
>>    /**
>>     * Return the connection username for this Realm.
>>     */
>>    public String getConnectionName() {
>>
>>        return (this.connectionName);
>>
>>    }
>>
>>
>>    /**
>>     * Set the connection username for this Realm.
>>     *
>>     * @param connectionName The new connection username
>>     */
>>    public void setConnectionName(String connectionName) {
>>
>>        this.connectionName = connectionName;
>>
>>    }
>>
>>
>>    /**
>>     * Return the connection password for this Realm.
>>     */
>>    public String getConnectionPassword() {
>>
>>        return (this.connectionPassword);
>>
>>    }
>>
>>
>>    /**
>>     * Set the connection password for this Realm.
>>     *
>>     * @param connectionPassword The new connection password
>>     */
>>    public void setConnectionPassword(String connectionPassword) {
>>
>>        this.connectionPassword = connectionPassword;
>>
>>    }
>>
>>
>>    /**
>>     * Return the connection URL for this Realm.
>>     */
>>    public String getConnectionURL() {
>>
>>        return (this.connectionURL);
>>
>>    }
>>
>>
>>    /**
>>     * Set the connection URL for this Realm.
>>     *
>>     * @param connectionURL The new connection URL
>>     */
>>    public void setConnectionURL(String connectionURL) {
>>
>>        this.connectionURL = connectionURL;
>>
>>    }
>>
>>
>>    /**
>>     * Return the JNDI context factory for this Realm.
>>     */
>>    public String getContextFactory() {
>>
>>        return (this.contextFactory);
>>
>>    }
>>
>>
>>    /**
>>     * Set the JNDI context factory for this Realm.
>>     *
>>     * @param contextFactory The new context factory
>>     */
>>    public void setContextFactory(String contextFactory) {
>>
>>        this.contextFactory = contextFactory;
>>
>>    }
>>
>>
>>    /**
>>     * Return the base element for role searches.
>>     */
>>    public String getRoleBase() {
>>
>>        return (this.roleBase);
>>
>>    }
>>
>>
>>    /**
>>     * Set the base element for role searches.
>>     *
>>     * @param roleBase The new base element
>>     */
>>    public void setRoleBase(String roleBase) {
>>
>>        this.roleBase = roleBase;
>>
>>    }
>>
>>
>>    /**
>>     * Return the role name attribute name for this Realm.
>>     */
>>    public String getRoleName() {
>>
>>        if (this.roleName != null)
>>            return (this.roleName[0]);
>>        else
>>            return (null);
>>
>>    }
>>
>>
>>    /**
>>     * Set the role name attribute name for this Realm.
>>     *
>>     * @param roleName The new role name attribute name
>>     */
>>    public void setRoleName(String roleName) {
>>
>>        if (roleName != null)
>>            this.roleName = new String[] { roleName };
>>        else
>>            this.roleName = null;
>>
>>    }
>>
>>
>>    /**
>>     * Return the message format pattern for selecting roles in this
> 
> Realm.
> 
>>     */
>>    public String getRoleSearch() {
>>
>>        return (this.roleSearch);
>>
>>    }
>>
>>
>>    /**
>>     * Set the message format pattern for selecting roles in this Realm.
>>     *
>>     * @param roleSearch The new role search pattern
>>     */
>>    public void setRoleSearch(String roleSearch) {
>>
>>        this.roleSearch = roleSearch;
>>        if (roleSearch == null)
>>            roleFormat = null;
>>        else
>>            roleFormat = new MessageFormat(roleSearch);
>>
>>    }
>>
>>
>>    /**
>>     * Return the "search subtree for roles" flag.
>>     */
>>    public boolean getRoleSubtree() {
>>
>>        return (this.roleSubtree);
>>
>>    }
>>
>>
>>    /**
>>     * Set the "search subtree for roles" flag.
>>     *
>>     * @param roleSubtree The new search flag
>>     */
>>    public void setRoleSubtree(boolean roleSubtree) {
>>
>>        this.roleSubtree = roleSubtree;
>>
>>    }
>>
>>
>>    /**
>>     * Return the password attribute used to retrieve the user password.
>>     */
>>    public String getUserPassword() {
>>
>>        if (this.userPassword != null)
>>            return (this.userPassword[0]);
>>        else
>>            return (null);
>>
>>    }
>>
>>
>>    /**
>>     * Set the password attribute used to retrieve the user password.
>>     *
>>     * @param userPassword The new password attribute
>>     */
>>    public void setUserPassword(String userPassword) {
>>
>>        if (userPassword != null)
>>            this.userPassword = new String[] { userPassword };
>>        else
>>            this.userPassword = null;
>>
>>    }
>>
>>
>>    /**
>>     * Return the message format pattern for selecting users in this
> 
> Realm.
> 
>>     */
>>    public String getUserPattern() {
>>
>>        return (this.userPattern);
>>
>>    }
>>
>>
>>    /**
>>     * Set the message format pattern for selecting users in this Realm.
>>     *
>>     * @param userPattern The new user pattern
>>     */
>>    public void setUserPattern(String userPattern) {
>>
>>        this.userPattern = userPattern;
>>        if (userPattern == null)
>>            userFormat = null;
>>        else
>>            userFormat = new MessageFormat(userPattern);
>>
>>    }
>>
>>
>>    // ---------------------------------------------------------- Realm
> 
> Methods
> 
>>
>>    /**
>>     * Return the Principal associated with the specified username and
>>     * credentials, if there is one; otherwise return <code>null</code>.
>>     *
>>     * If there are any errors with the JDBC connection, executing
>>     * the query or anything we return null (don't authenticate). This
>>     * event is also logged, and the connection will be closed so that
>>     * a subsequent request will automatically re-open it.
>>     *
>>     * @param username Username of the Principal to look up
>>     * @param credentials Password or other credentials to use in
>>     *  authenticating this username
>>     */
>>    public Principal authenticate(String username, String credentials) {
>>
>>        DirContext context = null;
>>
>>        try {
>>
>>            // Ensure that we have a directory context available
>>            context = open();
>>
>>            // Authenticate the specified username if possible
>>            Principal principal = authenticate(context,
>>                                               username, credentials);
>>
>>            // Release this context
>>            release(context);
>>
>>            // Return the authenticated Principal (if any)
>>            return (principal);
>>
>>        } catch (NamingException e) {
>>
>>            // Log the problem for posterity
>>            log(sm.getString("jndiRealm.exception"), e);
>>
>>            // Close the connection so that it gets reopened next time
>>            if (context != null)
>>                close(context);
>>
>>            // Return "not authenticated" for this request
>>            return (null);
>>
>>        }
>>
>>    }
>>
>>
>>    // -------------------------------------------------------- Package
> 
> Methods
> 
>>
>>    // ------------------------------------------------------ Protected
> 
> Methods
> 
>>
>>    /**
>>     * Return the Principal associated with the specified username and
>>     * credentials, if there is one; otherwise return <code>null</code>.
>>     *
>>     * @param username Username of the Principal to look up
>>     * @param credentials Password or other credentials to use in
>>     *  authenticating this username
>>     *
>>     * @exception NamingException if a directory server error occurs
>>     */
>>    public synchronized Principal authenticate(DirContext context,
>>                                               String username,
>>                                               String credentials)
>>        throws NamingException {
>>
>>        // Authenticate the specified username if possible
>>        String dn = getUserDN(context, username, credentials);
>>        if (dn == null)
>>            return (null);
>>
>>        // Look up the associated roles
>>        List roles = getRoles(context, username, dn);
>>
>>        // Create and return a suitable Principal for this user
>>        return (new GenericPrincipal(this, username, credentials, roles));
>>
>>    }
>>
>>
>>    /**
>>     * Close any open connection to the directory server for this Realm.
>>     *
>>     * @param context The directory context to be closed
>>     */
>>    protected void close(DirContext context) {
>>
>>        // Do nothing if there is no opened connection
>>        if (context == null)
>>            return;
>>
>>        // Close our opened connection
>>        try {
>>            if (debug >= 1)
>>                log("Closing directory context");
>>            context.close();
>>        } catch (NamingException e) {
>>            log(sm.getString("jndiRealm.close"), e);
>>        }
>>        this.context = null;
>>
>>    }
>>
>>
>>    /**
>>     * Return a short name for this Realm implementation.
>>     */
>>    protected String getName() {
>>
>>        return (this.name);
>>
>>    }
>>
>>
>>    /**
>>     * Return the password associated with the given principal's user
> 
> name.
> 
>>     */
>>    protected String getPassword(String username) {
>>
>>        return (null);
>>
>>    }
>>
>>
>>    /**
>>     * Return the Principal associated with the given user name.
>>     */
>>    protected Principal getPrincipal(String username) {
>>
>>        return (null);
>>
>>    }
>>
>>
>>    /**
>>     * Return a List of roles associated with the user with the specified
>>     * distinguished name.  If no roles are associated with this user, a
>>     * zero-length List is returned.
>>     *
>>     * @param context The directory context we are searching
>>     * @param username The username of the user to be checked
>>     * @param dn Distinguished name of the user to be checked
>>     *
>>     * @exception NamingException if a directory server error occurs
>>     */
>>    protected List getRoles(DirContext context,
>>                            String username, String dn)
>>        throws NamingException {
>>
>>        if (debug >= 2)
>>            log("getRoles(" + dn + ")");
>>
>>        // Are we configured to do role searches?
>>        ArrayList list = new ArrayList();
>>        if ((roleFormat == null) || (roleName == null))
>>            return (list);
>>
>>        // Set up parameters for an appropriate search
>>        String filter = roleFormat.format(new String[] { dn, username });
>>        SearchControls controls = new SearchControls();
>>        if (roleSubtree)
>>            controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
>>        else
>>            controls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
>>        controls.setReturningAttributes(roleName);
>>
>>        // Perform the configured search and process the results
>>        if (debug >= 3) {
>>            log("  Searching role base '" + roleBase + "' for attribute '"
> 
> +
> 
>>                roleName[0] + "'");
>>            log("  With filter expression '" + filter + "'");
>>        }
>>        NamingEnumeration results =
>>            context.search(roleBase, filter, controls);
>>        if (results == null)
>>            return (list);  // Should never happen, but just in case ...
>>        while (results.hasMore()) {
>>            SearchResult result = (SearchResult) results.next();
>>            Attributes attrs = result.getAttributes();
>>            if (attrs == null) {
>>                log( "attrs null, here is result: " + result.toString() );
>>                continue;
>>            }
>>            Attribute attr = attrs.get(roleName[0]);
>>            if (attr != null) {
>>                String role = (String) attr.get();
>>                if (debug >= 3)
>>                    log("  Found role '" + role + "'");
>>                list.add(role);
>>            }
>>        }
>>
>>        // Return the completed list of roles
>>        if (debug >= 2)
>>            log("  Returning " + list.size() + " roles");
>>        return (list);
>>
>>    }
>>
>>
>>    /**
>>     * Return the distinguished name of an authenticated user (if
> 
> successful)
> 
>>     * or <code>null</code> if authentication is unsuccessful.
>>     *
>>     * @param context The directory context we are accessing
>>     * @param username Username to be authenticated
>>     * @param credentials Authentication credentials
>>     *
>>     * @exception NamingException if a directory server error occurs
>>     */
>>    protected String getUserDN(DirContext context,
>>                               String username, String credentials)
>>        throws NamingException {
>>
>>        if (debug >= 2)
>>            log("getUserDN(" + username + ")");
>>        if (username == null)
>>            return (null);
>>        if ((userFormat == null) || (userPassword == null))
>>            return (null);
>>        if (userPassword[0]==null ||userPassword[0].length()==0)
>>            return (null);
>>
>>        // Retrieve the user password attribute for this user
>>        String dn = userFormat.format(new String[] { username });
>>        if (debug >= 3)
>>            log("  dn=" + dn);
>>        Attributes attrs = null;
>>        try {
>>            attrs = context.getAttributes(dn, userPassword);
>>        } catch (NameNotFoundException e) {
>>            return (null);
>>        }
>>        if (attrs == null)
>>            return (null);
>>        if (debug >= 3)
>>            log("  retrieving attribute " + userPassword[0]);
>>        Attribute attr = attrs.get(userPassword[0]);
>>        if (attr == null)
>>            return (null);
>>        if (debug >= 3)
>>            log("  retrieving value");
>>        Object value = attr.get();
>>        if (value == null)
>>            return (null);
>>        String valueString = null;
>>        if (value instanceof byte[])
>>            valueString = new String((byte[]) value);
>>        else
>>            valueString = value.toString();
>>
>>
>>        // Validate the credentials specified by the user
>>        if (debug >= 3)
>>            log("  validating credentials");
>>
>>        boolean validated = false;
>>        if (hasMessageDigest()) {
>>            //iPlant crap - is encoded base64 and crapified
>>            if (valueString.startsWith("{")) {
>>                valueString = valueString.substring(5);
>>                md.reset();
>>                md.update(credentials.getBytes());
>>                String b64 = new
> 
> String(org.apache.catalina.util.Base64.encode(md.digest()));
> 
>>                validated = (b64.equals(valueString));
>>                log("JNDIRealm(equalsIgnoreCase):
> 
> credentials=["+b64+"]\tvs\t valueString=["+valueString+"]");
> 
>>            } else {
>>                // Hex hashes should be compared case-insensitive
>>                validated =
> 
> (digest(credentials).equalsIgnoreCase(valueString));
> 
>>            }
>>        } else {
>>            validated = (digest(credentials).equals(valueString));
>>        }
>>
>>        if (validated) {
>>            if (debug >= 2)
>>                log(sm.getString("jndiRealm.authenticateSuccess",
>>                                 username));
>>        } else {
>>            if (debug >= 2)
>>                log(sm.getString("jndiRealm.authenticateFailure",
>>                                 username));
>>            return (null);
>>        }
>>        return (dn);
>>
>>    }
>>
>>
>>    /**
>>     * Open (if necessary) and return a connection to the configured
>>     * directory server for this Realm.
>>     *
>>     * @exception NamingException if a directory server error occurs
>>     */
>>    protected DirContext open() throws NamingException {
>>
>>        // Do nothing if there is a directory server connection already
> 
> open
> 
>>        if (context != null)
>>            return (context);
>>
>>        // Establish a connection and retrieve the initial context
>>        if (debug >= 1)
>>            log("Connecting to URL " + connectionURL);
>>        Hashtable env = new Hashtable();
>>        env.put(Context.INITIAL_CONTEXT_FACTORY, contextFactory);
>>        if (connectionName != null)
>>            env.put(Context.SECURITY_PRINCIPAL, connectionName);
>>        if (connectionPassword != null)
>>            env.put(Context.SECURITY_CREDENTIALS, connectionPassword);
>>        if (connectionURL != null)
>>            env.put(Context.PROVIDER_URL, connectionURL);
>>        context = new InitialDirContext(env);
>>        return (context);
>>
>>    }
>>
>>
>>    /**
>>     * Release our use of this connection so that it can be recycled.
>>     *
>>     * @param context The directory context to release
>>     */
>>    protected void release(DirContext context) {
>>
>>        ; // NO-OP since we are not pooling anything
>>
>>    }
>>
>>
>>    // ------------------------------------------------------ Lifecycle
> 
> Methods
> 
>>
>>    /**
>>     * Prepare for active use of the public methods of this Component.
>>     *
>>     * @exception IllegalStateException if this component has already been
>>     *  started
>>     * @exception LifecycleException if this component detects a fatal
> 
> error
> 
>>     *  that prevents it from being started
>>     */
>>    public void start() throws LifecycleException {
>>
>>        // Validate that we can open our connection
>>        try {
>>            open();
>>        } catch (NamingException e) {
>>            throw new LifecycleException(sm.getString("jndiRealm.open"),
> 
> e);
> 
>>        }
>>
>>        // Perform normal superclass initialization
>>        super.start();
>>
>>    }
>>
>>
>>    /**
>>     * Gracefully shut down active use of the public methods of this
> 
> Component.
> 
>>     *
>>     * @exception IllegalStateException if this component has not been
>>     *  started
>>     * @exception LifecycleException if this component detects a fatal
> 
> error
> 
>>     *  that needs to be reported
>>     */
>>    public void stop() throws LifecycleException {
>>
>>        // Perform normal superclass finalization
>>        super.stop();
>>
>>        // Close any open directory server connection
>>        close(this.context);
>>
>>    }
>>
>>
>>
>>}
>>
>>
> 
> 
> 
> ----------------------------------------------------------------------------
> ----
> 
> 
> 
>>--
>>To unsubscribe, e-mail:
> 
> <ma...@jakarta.apache.org>
> 
>>For additional commands, e-mail:
> 
> <ma...@jakarta.apache.org>
> 
> 
> --
> To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
> For additional commands, e-mail: <ma...@jakarta.apache.org>
> 
> 
> 



--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: JNDI Realm Help - (using iplanet)

Posted by Randy Secrist <to...@secristfamily.com>.
Thank you Tim, your response has helped greatly!  I was able to compile and
use your implementation of IPlanetRealm to get it working!  Now I just need
to look at the 4.1.x JNDIRealm to see if it fixes that base64 encoding
problems.

Do yo know if that base64 problem carries over into the JDBCRealm at all?
(For using SHA with say - mysql?)

Randy

----- Original Message -----
From: "Tim Funk" <fu...@joedog.org>
To: "Tomcat Users List" <to...@jakarta.apache.org>
Sent: Tuesday, August 20, 2002 12:04 PM
Subject: Re: JNDI Realm Help - (using iplanet)


> IPlanet with SHA does not work together in 4.0.4. The password coming
> back from iPlanet is compared incorrectly with respect to digesting the
> user provided password.
>
> You have 3 alternatives:
> 1) Hack JNDIRealm (Attached is one I did and am using until upgrading to
> 4.1.X)
> 2) Use 4.1.X and bind as the user
> 3) Use JNDIRealm from the 4.1.X tree and bind as the user
>
> -Tim
>
> Randy Secrist wrote:
> > Hello,
> >
> > I am trying to get TC (4.0.4) to establish a working JNDI realm using
> > iplanet's directory server.  I am using FORM based login and have this
> > working as a JDBC realm previously.
> >
> > As you can see below, I would like to keep my users and roles in
> > ou=warnertruck,ou=truckcenter,dc=secristfamily,dc=com.  Iplanet sets up
each
> > user with a role nsrole, and nsroledn.  I have tried switching the
values
> > for roleName, and roleSearch, and since iplanet stores passwords using
SHA,
> > I even threw on a digest="SHA" in the realm tag.  I have messed with
this
> > for months now, and have searched the web extensivly for help.  Would
> > someone please tell me what I need to do to get this working?
> >
> > If I can actually get this working, I will be most elated!
> >
> > Randy Secrist
> >
>


----------------------------------------------------------------------------
----


> /*
>  * The Apache Software License, Version 1.1
>  *
>  * Copyright (c) 1999 The Apache Software Foundation.  All rights
>  * reserved.
>  *
>  * Redistribution and use in source and binary forms, with or without
>  * modification, are permitted provided that the following conditions
>  * are met:
>  *
>  * 1. Redistributions of source code must retain the above copyright
>  *    notice, this list of conditions and the following disclaimer.
>  *
>  * 2. Redistributions in binary form must reproduce the above copyright
>  *    notice, this list of conditions and the following disclaimer in
>  *    the documentation and/or other materials provided with the
>  *    distribution.
>  *
>  * 3. The end-user documentation included with the redistribution, if
>  *    any, must include the following acknowlegement:
>  *       "This product includes software developed by the
>  *        Apache Software Foundation (http://www.apache.org/)."
>  *    Alternately, this acknowlegement may appear in the software itself,
>  *    if and wherever such third-party acknowlegements normally appear.
>  *
>  * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
>  *    Foundation" must not be used to endorse or promote products derived
>  *    from this software without prior written permission. For written
>  *    permission, please contact apache@apache.org.
>  *
>  * 5. Products derived from this software may not be called "Apache"
>  *    nor may "Apache" appear in their names without prior written
>  *    permission of the Apache Group.
>  *
>  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
>  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
>  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
>  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
>  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
>  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
>  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
>  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
>  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
>  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
>  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
>  * SUCH DAMAGE.
>  * ====================================================================
>  *
>  * This software consists of voluntary contributions made by many
>  * individuals on behalf of the Apache Software Foundation.  For more
>  * information on the Apache Software Foundation, please see
>  * <http://www.apache.org/>.
>  *
>  * [Additional notices, if required by prior licensing conditions]
>  *
>  */
>
>
> package org.joedog.scrapme.ldap;
>
> import java.security.Principal;
> import java.text.MessageFormat;
> import java.util.ArrayList;
> import java.util.Hashtable;
> import java.util.List;
> import javax.naming.Context;
> import javax.naming.NameNotFoundException;
> 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 org.apache.catalina.LifecycleException;
> import org.apache.catalina.Realm;
> import org.apache.catalina.util.StringManager;
> import org.apache.catalina.realm.*;
>
>
> /**
>  * <h1>For temporary usage with Tomcat 4.0.4 or earlier. This
>  *     is a copy of the JNDIRealm with a few patches!
>  * </h1>
>  *
>  * <br /><br /><br />
>  * <p>Implementation of <strong>Realm</strong> that works with a directory
>  * server accessed via the Java Naming and Directory Interface (JNDI)
APIs.
>  * The following constraints are imposed on the data structure in the
>  * underlying directory server:</p>
>  * <ul>
>  * <li>Each user that can be authenticated is represented by an individual
>  *     element in the top level <code>DirContext</code> that is accessed
>  *     via the <code>connectionURL</code> property.  This element has the
>  *     following characteristics:
>  *     <ul>
>  *     <li>The distinguished name (<code>dn</code>) attribute of this
element
>  *         contains the username that is being presented for
authentication.
>  *         </li>
>  *     <li>The distinguished name can be represented by a pattern passed
to
>  *         an instance of <code>MessageFormat</code>, where the string
"{0}"
>  *         in the pattern is replaced by the username being
presented.</li>
>  *     <li>The element for this user contains an attribute named by the
>  *         <code>userPassword</code> property.  The value of this
attribute
>  *         is retrieved for use in authentication.</li>
>  *     <li>The value of the user password attribute is either a cleartext
>  *         String, or the result of passing a cleartext String through the
>  *         <code>RealmBase.digest()</code> method (using the standard
digest
>  *         support included in <code>RealmBase</code>).
>  *     <li>The user is considered to be authenticated if the presented
>  *         credentials (after being passed through
>  *         <code>RealmBase.digest()</code>) are equal to the retrieved
value
>  *         for the user password attribute.</li>
>  *     </ul></li>
>  * <li>Each group of users that has been assigned a particular role is
>  *     represented by an individual element in the top level
>  *     <code>DirContext</code> that is accessed via the
>  *     <code>connectionURL</code> property.  This element has the
following
>  *     characteristics:
>  *     <ul>
>  *     <li>The set of all possible groups of interest can be selected by a
>  *         search pattern configured by the <code>roleSearch</code>
>  *         property.</li>
>  *     <li>The <code>roleSearch</code> pattern optionally includes pattern
>  *         replacements "{0}" for the distinguished name, and/or "{1}" for
>  *         the username, of the authenticated user for which roles will be
>  *         retrieved.</li>
>  *     <li>The <code>roleBase</code> property can be set to the element
that
>  *         is the base of the search for matching roles.  If not
specified,
>  *         the entire context will be searched.</li>
>  *     <li>The <code>roleSubtree</code> property can be set to
>  *         <code>true</code> if you wish to search the entire subtree of
the
>  *         directory context.  The default value of <code>false</code>
>  *         requests a search of only the current level.</li>
>  *     <li>The element includes an attribute (whose name is configured by
>  *         the <code>roleName</code> property) containing the name of the
>  *         role represented by this element.</li>
>  *     </ul></li>
>  * <li>Note that the standard <code>&lt;security-role-ref&gt;</code>
element in
>  *     the web application deployment descriptor allows applications to
refer
>  *     to roles programmatically by names other than those used in the
>  *     directory server itself.</li>
>  * </ul>
>  *
>  * <p><strong>TODO</strong> - Support connection pooling (including
message
>  * format objects) so that <code>authenticate()</code> does not have to be
>  * synchronized.</p>
>  *
>  * <p><strong>TODO</strong> - Get rid of this class and use JNDIRealm. But
>  * JNDIRealm needs patched because IPLanet returns Base64 SHA passwords
>  * and the the current JNDIRealm doesn't handle that.
>  * </p>
>  *
>  * @author Tim Funk
>  * @version $Revision: 1.1.1.1 $ $Date: 2002/06/26 18:21:21 $
>  */
>
> public class IPlanetRealm extends RealmBase {
>
>
>     // ----------------------------------------------------- Instance
Variables
>
>
>     /**
>      * The connection username for the server we will contact.
>      */
>     protected String connectionName = null;
>
>
>     /**
>      * The connection password for the server we will contact.
>      */
>     protected String connectionPassword = null;
>
>
>     /**
>      * The connection URL for the server we will contact.
>      */
>     protected String connectionURL = null;
>
>
>     /**
>      * The directory context linking us to our directory server.
>      */
>     protected DirContext context = null;
>
>
>     /**
>      * The JNDI context factory used to acquire our InitialContext.  By
>      * default, assumes use of an LDAP server using the standard JNDI LDAP
>      * provider.
>      */
>     protected String contextFactory = "com.sun.jndi.ldap.LdapCtxFactory";
>
>
>     /**
>      * Descriptive information about this Realm implementation.
>      */
>     protected static final String info =
>         "org.apache.catalina.realm.JNDIRealm/1.0";
>
>
>     /**
>      * Descriptive information about this Realm implementation.
>      */
>     protected static final String name = "JNDIRealm";
>
>
>     /**
>      * The base element for role searches.
>      */
>     protected String roleBase = "";
>
>
>     /**
>      * The MessageFormat object associated with the current
>      * <code>roleSearch</code>.
>      */
>     protected MessageFormat roleFormat = null;
>
>
>     /**
>      * The name of the attribute containing the role name.
>      */
>     protected String roleName[] = null;
>
>
>     /**
>      * The message format used to select roles for a user, with "{0}"
marking
>      * the spot where the distinguished name of the user goes.
>      */
>     protected String roleSearch = null;
>
>
>     /**
>      * Should we search the entire subtree for matching memberships?
>      */
>     protected boolean roleSubtree = false;
>
>
>     /**
>      * The MessageFormat object associated with the current
>      * <code>userPattern</code>.
>      */
>     protected MessageFormat userFormat = null;
>
>
>     /**
>      * The attribute name used to retrieve the user password.
>      */
>     protected String userPassword[] = null;
>
>
>     /**
>      * The message format used to select a user, with "{0}" marking the
>      * spot where the specified username goes.
>      */
>     protected String userPattern = null;
>
>
>     // -------------------------------------------------------------
Properties
>
>
>     /**
>      * Return the connection username for this Realm.
>      */
>     public String getConnectionName() {
>
>         return (this.connectionName);
>
>     }
>
>
>     /**
>      * Set the connection username for this Realm.
>      *
>      * @param connectionName The new connection username
>      */
>     public void setConnectionName(String connectionName) {
>
>         this.connectionName = connectionName;
>
>     }
>
>
>     /**
>      * Return the connection password for this Realm.
>      */
>     public String getConnectionPassword() {
>
>         return (this.connectionPassword);
>
>     }
>
>
>     /**
>      * Set the connection password for this Realm.
>      *
>      * @param connectionPassword The new connection password
>      */
>     public void setConnectionPassword(String connectionPassword) {
>
>         this.connectionPassword = connectionPassword;
>
>     }
>
>
>     /**
>      * Return the connection URL for this Realm.
>      */
>     public String getConnectionURL() {
>
>         return (this.connectionURL);
>
>     }
>
>
>     /**
>      * Set the connection URL for this Realm.
>      *
>      * @param connectionURL The new connection URL
>      */
>     public void setConnectionURL(String connectionURL) {
>
>         this.connectionURL = connectionURL;
>
>     }
>
>
>     /**
>      * Return the JNDI context factory for this Realm.
>      */
>     public String getContextFactory() {
>
>         return (this.contextFactory);
>
>     }
>
>
>     /**
>      * Set the JNDI context factory for this Realm.
>      *
>      * @param contextFactory The new context factory
>      */
>     public void setContextFactory(String contextFactory) {
>
>         this.contextFactory = contextFactory;
>
>     }
>
>
>     /**
>      * Return the base element for role searches.
>      */
>     public String getRoleBase() {
>
>         return (this.roleBase);
>
>     }
>
>
>     /**
>      * Set the base element for role searches.
>      *
>      * @param roleBase The new base element
>      */
>     public void setRoleBase(String roleBase) {
>
>         this.roleBase = roleBase;
>
>     }
>
>
>     /**
>      * Return the role name attribute name for this Realm.
>      */
>     public String getRoleName() {
>
>         if (this.roleName != null)
>             return (this.roleName[0]);
>         else
>             return (null);
>
>     }
>
>
>     /**
>      * Set the role name attribute name for this Realm.
>      *
>      * @param roleName The new role name attribute name
>      */
>     public void setRoleName(String roleName) {
>
>         if (roleName != null)
>             this.roleName = new String[] { roleName };
>         else
>             this.roleName = null;
>
>     }
>
>
>     /**
>      * Return the message format pattern for selecting roles in this
Realm.
>      */
>     public String getRoleSearch() {
>
>         return (this.roleSearch);
>
>     }
>
>
>     /**
>      * Set the message format pattern for selecting roles in this Realm.
>      *
>      * @param roleSearch The new role search pattern
>      */
>     public void setRoleSearch(String roleSearch) {
>
>         this.roleSearch = roleSearch;
>         if (roleSearch == null)
>             roleFormat = null;
>         else
>             roleFormat = new MessageFormat(roleSearch);
>
>     }
>
>
>     /**
>      * Return the "search subtree for roles" flag.
>      */
>     public boolean getRoleSubtree() {
>
>         return (this.roleSubtree);
>
>     }
>
>
>     /**
>      * Set the "search subtree for roles" flag.
>      *
>      * @param roleSubtree The new search flag
>      */
>     public void setRoleSubtree(boolean roleSubtree) {
>
>         this.roleSubtree = roleSubtree;
>
>     }
>
>
>     /**
>      * Return the password attribute used to retrieve the user password.
>      */
>     public String getUserPassword() {
>
>         if (this.userPassword != null)
>             return (this.userPassword[0]);
>         else
>             return (null);
>
>     }
>
>
>     /**
>      * Set the password attribute used to retrieve the user password.
>      *
>      * @param userPassword The new password attribute
>      */
>     public void setUserPassword(String userPassword) {
>
>         if (userPassword != null)
>             this.userPassword = new String[] { userPassword };
>         else
>             this.userPassword = null;
>
>     }
>
>
>     /**
>      * Return the message format pattern for selecting users in this
Realm.
>      */
>     public String getUserPattern() {
>
>         return (this.userPattern);
>
>     }
>
>
>     /**
>      * Set the message format pattern for selecting users in this Realm.
>      *
>      * @param userPattern The new user pattern
>      */
>     public void setUserPattern(String userPattern) {
>
>         this.userPattern = userPattern;
>         if (userPattern == null)
>             userFormat = null;
>         else
>             userFormat = new MessageFormat(userPattern);
>
>     }
>
>
>     // ---------------------------------------------------------- Realm
Methods
>
>
>     /**
>      * Return the Principal associated with the specified username and
>      * credentials, if there is one; otherwise return <code>null</code>.
>      *
>      * If there are any errors with the JDBC connection, executing
>      * the query or anything we return null (don't authenticate). This
>      * event is also logged, and the connection will be closed so that
>      * a subsequent request will automatically re-open it.
>      *
>      * @param username Username of the Principal to look up
>      * @param credentials Password or other credentials to use in
>      *  authenticating this username
>      */
>     public Principal authenticate(String username, String credentials) {
>
>         DirContext context = null;
>
>         try {
>
>             // Ensure that we have a directory context available
>             context = open();
>
>             // Authenticate the specified username if possible
>             Principal principal = authenticate(context,
>                                                username, credentials);
>
>             // Release this context
>             release(context);
>
>             // Return the authenticated Principal (if any)
>             return (principal);
>
>         } catch (NamingException e) {
>
>             // Log the problem for posterity
>             log(sm.getString("jndiRealm.exception"), e);
>
>             // Close the connection so that it gets reopened next time
>             if (context != null)
>                 close(context);
>
>             // Return "not authenticated" for this request
>             return (null);
>
>         }
>
>     }
>
>
>     // -------------------------------------------------------- Package
Methods
>
>
>     // ------------------------------------------------------ Protected
Methods
>
>
>     /**
>      * Return the Principal associated with the specified username and
>      * credentials, if there is one; otherwise return <code>null</code>.
>      *
>      * @param username Username of the Principal to look up
>      * @param credentials Password or other credentials to use in
>      *  authenticating this username
>      *
>      * @exception NamingException if a directory server error occurs
>      */
>     public synchronized Principal authenticate(DirContext context,
>                                                String username,
>                                                String credentials)
>         throws NamingException {
>
>         // Authenticate the specified username if possible
>         String dn = getUserDN(context, username, credentials);
>         if (dn == null)
>             return (null);
>
>         // Look up the associated roles
>         List roles = getRoles(context, username, dn);
>
>         // Create and return a suitable Principal for this user
>         return (new GenericPrincipal(this, username, credentials, roles));
>
>     }
>
>
>     /**
>      * Close any open connection to the directory server for this Realm.
>      *
>      * @param context The directory context to be closed
>      */
>     protected void close(DirContext context) {
>
>         // Do nothing if there is no opened connection
>         if (context == null)
>             return;
>
>         // Close our opened connection
>         try {
>             if (debug >= 1)
>                 log("Closing directory context");
>             context.close();
>         } catch (NamingException e) {
>             log(sm.getString("jndiRealm.close"), e);
>         }
>         this.context = null;
>
>     }
>
>
>     /**
>      * Return a short name for this Realm implementation.
>      */
>     protected String getName() {
>
>         return (this.name);
>
>     }
>
>
>     /**
>      * Return the password associated with the given principal's user
name.
>      */
>     protected String getPassword(String username) {
>
>         return (null);
>
>     }
>
>
>     /**
>      * Return the Principal associated with the given user name.
>      */
>     protected Principal getPrincipal(String username) {
>
>         return (null);
>
>     }
>
>
>     /**
>      * Return a List of roles associated with the user with the specified
>      * distinguished name.  If no roles are associated with this user, a
>      * zero-length List is returned.
>      *
>      * @param context The directory context we are searching
>      * @param username The username of the user to be checked
>      * @param dn Distinguished name of the user to be checked
>      *
>      * @exception NamingException if a directory server error occurs
>      */
>     protected List getRoles(DirContext context,
>                             String username, String dn)
>         throws NamingException {
>
>         if (debug >= 2)
>             log("getRoles(" + dn + ")");
>
>         // Are we configured to do role searches?
>         ArrayList list = new ArrayList();
>         if ((roleFormat == null) || (roleName == null))
>             return (list);
>
>         // Set up parameters for an appropriate search
>         String filter = roleFormat.format(new String[] { dn, username });
>         SearchControls controls = new SearchControls();
>         if (roleSubtree)
>             controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
>         else
>             controls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
>         controls.setReturningAttributes(roleName);
>
>         // Perform the configured search and process the results
>         if (debug >= 3) {
>             log("  Searching role base '" + roleBase + "' for attribute '"
+
>                 roleName[0] + "'");
>             log("  With filter expression '" + filter + "'");
>         }
>         NamingEnumeration results =
>             context.search(roleBase, filter, controls);
>         if (results == null)
>             return (list);  // Should never happen, but just in case ...
>         while (results.hasMore()) {
>             SearchResult result = (SearchResult) results.next();
>             Attributes attrs = result.getAttributes();
>             if (attrs == null) {
>                 log( "attrs null, here is result: " + result.toString() );
>                 continue;
>             }
>             Attribute attr = attrs.get(roleName[0]);
>             if (attr != null) {
>                 String role = (String) attr.get();
>                 if (debug >= 3)
>                     log("  Found role '" + role + "'");
>                 list.add(role);
>             }
>         }
>
>         // Return the completed list of roles
>         if (debug >= 2)
>             log("  Returning " + list.size() + " roles");
>         return (list);
>
>     }
>
>
>     /**
>      * Return the distinguished name of an authenticated user (if
successful)
>      * or <code>null</code> if authentication is unsuccessful.
>      *
>      * @param context The directory context we are accessing
>      * @param username Username to be authenticated
>      * @param credentials Authentication credentials
>      *
>      * @exception NamingException if a directory server error occurs
>      */
>     protected String getUserDN(DirContext context,
>                                String username, String credentials)
>         throws NamingException {
>
>         if (debug >= 2)
>             log("getUserDN(" + username + ")");
>         if (username == null)
>             return (null);
>         if ((userFormat == null) || (userPassword == null))
>             return (null);
>         if (userPassword[0]==null ||userPassword[0].length()==0)
>             return (null);
>
>         // Retrieve the user password attribute for this user
>         String dn = userFormat.format(new String[] { username });
>         if (debug >= 3)
>             log("  dn=" + dn);
>         Attributes attrs = null;
>         try {
>             attrs = context.getAttributes(dn, userPassword);
>         } catch (NameNotFoundException e) {
>             return (null);
>         }
>         if (attrs == null)
>             return (null);
>         if (debug >= 3)
>             log("  retrieving attribute " + userPassword[0]);
>         Attribute attr = attrs.get(userPassword[0]);
>         if (attr == null)
>             return (null);
>         if (debug >= 3)
>             log("  retrieving value");
>         Object value = attr.get();
>         if (value == null)
>             return (null);
>         String valueString = null;
>         if (value instanceof byte[])
>             valueString = new String((byte[]) value);
>         else
>             valueString = value.toString();
>
>
>         // Validate the credentials specified by the user
>         if (debug >= 3)
>             log("  validating credentials");
>
>         boolean validated = false;
>         if (hasMessageDigest()) {
>             //iPlant crap - is encoded base64 and crapified
>             if (valueString.startsWith("{")) {
>                 valueString = valueString.substring(5);
>                 md.reset();
>                 md.update(credentials.getBytes());
>                 String b64 = new
String(org.apache.catalina.util.Base64.encode(md.digest()));
>                 validated = (b64.equals(valueString));
>                 log("JNDIRealm(equalsIgnoreCase):
credentials=["+b64+"]\tvs\t valueString=["+valueString+"]");
>             } else {
>                 // Hex hashes should be compared case-insensitive
>                 validated =
(digest(credentials).equalsIgnoreCase(valueString));
>             }
>         } else {
>             validated = (digest(credentials).equals(valueString));
>         }
>
>         if (validated) {
>             if (debug >= 2)
>                 log(sm.getString("jndiRealm.authenticateSuccess",
>                                  username));
>         } else {
>             if (debug >= 2)
>                 log(sm.getString("jndiRealm.authenticateFailure",
>                                  username));
>             return (null);
>         }
>         return (dn);
>
>     }
>
>
>     /**
>      * Open (if necessary) and return a connection to the configured
>      * directory server for this Realm.
>      *
>      * @exception NamingException if a directory server error occurs
>      */
>     protected DirContext open() throws NamingException {
>
>         // Do nothing if there is a directory server connection already
open
>         if (context != null)
>             return (context);
>
>         // Establish a connection and retrieve the initial context
>         if (debug >= 1)
>             log("Connecting to URL " + connectionURL);
>         Hashtable env = new Hashtable();
>         env.put(Context.INITIAL_CONTEXT_FACTORY, contextFactory);
>         if (connectionName != null)
>             env.put(Context.SECURITY_PRINCIPAL, connectionName);
>         if (connectionPassword != null)
>             env.put(Context.SECURITY_CREDENTIALS, connectionPassword);
>         if (connectionURL != null)
>             env.put(Context.PROVIDER_URL, connectionURL);
>         context = new InitialDirContext(env);
>         return (context);
>
>     }
>
>
>     /**
>      * Release our use of this connection so that it can be recycled.
>      *
>      * @param context The directory context to release
>      */
>     protected void release(DirContext context) {
>
>         ; // NO-OP since we are not pooling anything
>
>     }
>
>
>     // ------------------------------------------------------ Lifecycle
Methods
>
>
>     /**
>      * Prepare for active use of the public methods of this Component.
>      *
>      * @exception IllegalStateException if this component has already been
>      *  started
>      * @exception LifecycleException if this component detects a fatal
error
>      *  that prevents it from being started
>      */
>     public void start() throws LifecycleException {
>
>         // Validate that we can open our connection
>         try {
>             open();
>         } catch (NamingException e) {
>             throw new LifecycleException(sm.getString("jndiRealm.open"),
e);
>         }
>
>         // Perform normal superclass initialization
>         super.start();
>
>     }
>
>
>     /**
>      * Gracefully shut down active use of the public methods of this
Component.
>      *
>      * @exception IllegalStateException if this component has not been
>      *  started
>      * @exception LifecycleException if this component detects a fatal
error
>      *  that needs to be reported
>      */
>     public void stop() throws LifecycleException {
>
>         // Perform normal superclass finalization
>         super.stop();
>
>         // Close any open directory server connection
>         close(this.context);
>
>     }
>
>
>
> }
>
>


----------------------------------------------------------------------------
----


> --
> To unsubscribe, e-mail:
<ma...@jakarta.apache.org>
> For additional commands, e-mail:
<ma...@jakarta.apache.org>


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: JNDI Realm Help - (using iplanet)

Posted by Tim Funk <fu...@joedog.org>.
IPlanet with SHA does not work together in 4.0.4. The password coming 
back from iPlanet is compared incorrectly with respect to digesting the 
user provided password.

You have 3 alternatives:
1) Hack JNDIRealm (Attached is one I did and am using until upgrading to 
4.1.X)
2) Use 4.1.X and bind as the user
3) Use JNDIRealm from the 4.1.X tree and bind as the user

-Tim

Randy Secrist wrote:
> Hello,
> 
> I am trying to get TC (4.0.4) to establish a working JNDI realm using
> iplanet's directory server.  I am using FORM based login and have this
> working as a JDBC realm previously.
> 
> As you can see below, I would like to keep my users and roles in
> ou=warnertruck,ou=truckcenter,dc=secristfamily,dc=com.  Iplanet sets up each
> user with a role nsrole, and nsroledn.  I have tried switching the values
> for roleName, and roleSearch, and since iplanet stores passwords using SHA,
> I even threw on a digest="SHA" in the realm tag.  I have messed with this
> for months now, and have searched the web extensivly for help.  Would
> someone please tell me what I need to do to get this working?
> 
> If I can actually get this working, I will be most elated!
> 
> Randy Secrist
>