001/*
002 *   Licensed to the Apache Software Foundation (ASF) under one
003 *   or more contributor license agreements.  See the NOTICE file
004 *   distributed with this work for additional information
005 *   regarding copyright ownership.  The ASF licenses this file
006 *   to you under the Apache License, Version 2.0 (the
007 *   "License"); you may not use this file except in compliance
008 *   with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *   Unless required by applicable law or agreed to in writing,
013 *   software distributed under the License is distributed on an
014 *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *   KIND, either express or implied.  See the License for the
016 *   specific language governing permissions and limitations
017 *   under the License.
018 *
019 */
020package org.apache.directory.server.protocol.shared.kerberos;
021
022
023import java.nio.ByteBuffer;
024
025import org.apache.directory.api.ldap.model.constants.Loggers;
026import org.apache.directory.api.ldap.model.constants.SchemaConstants;
027import org.apache.directory.api.ldap.model.cursor.Cursor;
028import org.apache.directory.api.ldap.model.entry.Entry;
029import org.apache.directory.api.ldap.model.entry.Value;
030import org.apache.directory.api.ldap.model.filter.EqualityNode;
031import org.apache.directory.api.ldap.model.filter.ExprNode;
032import org.apache.directory.api.ldap.model.message.AliasDerefMode;
033import org.apache.directory.api.ldap.model.message.SearchScope;
034import org.apache.directory.api.ldap.model.name.Dn;
035import org.apache.directory.api.ldap.model.schema.AttributeType;
036import org.apache.directory.api.ldap.model.schema.SchemaManager;
037import org.apache.directory.server.core.api.CoreSession;
038import org.apache.directory.server.i18n.I18n;
039import org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntry;
040import org.apache.directory.shared.kerberos.KerberosAttribute;
041import org.apache.directory.shared.kerberos.codec.types.EncryptionType;
042import org.apache.directory.shared.kerberos.components.EncryptionKey;
043import org.slf4j.Logger;
044import org.slf4j.LoggerFactory;
045
046
047/**
048 * Commonly used store utility operations.
049 *
050 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
051 */
052public final class StoreUtils
053{
054    /** Loggers for this class */
055    private static final Logger LOG = LoggerFactory.getLogger( StoreUtils.class );
056    private static final Logger LOG_KRB = LoggerFactory.getLogger( Loggers.KERBEROS_LOG.getName() );
057
058
059    private StoreUtils()
060    {
061    }
062
063
064    /**
065     * Creates a Entry for a PrincipalStoreEntry, doing what a state 
066     * factory does but for Entry instead of Attributes.
067     *
068     * @param session the session to use to access the directory's registries
069     * @param dn the distinguished name of the principal to be 
070     * @param principalEntry the principal entry to convert into a Entry
071     * @return the resultant server entry for the PrincipalStoreEntry argument
072     * @throws Exception if there are problems accessing registries
073     */
074    public static Entry toServerEntry( CoreSession session, Dn dn, PrincipalStoreEntry principalEntry )
075        throws Exception
076    {
077        Entry outAttrs = session.getDirectoryService().newEntry( dn );
078
079        // process the objectClass attribute
080        outAttrs.add( SchemaConstants.OBJECT_CLASS_AT,
081            SchemaConstants.TOP_OC, SchemaConstants.UID_OBJECT_AT,
082            "uidObject", SchemaConstants.EXTENSIBLE_OBJECT_OC,
083            SchemaConstants.PERSON_OC, SchemaConstants.ORGANIZATIONAL_PERSON_OC,
084            SchemaConstants.INET_ORG_PERSON_OC, SchemaConstants.KRB5_PRINCIPAL_OC,
085            "krb5KDCEntry" );
086
087        outAttrs.add( SchemaConstants.UID_AT, principalEntry.getUserId() );
088        outAttrs.add( KerberosAttribute.APACHE_SAM_TYPE_AT, "7" );
089        outAttrs.add( SchemaConstants.SN_AT, principalEntry.getUserId() );
090        outAttrs.add( SchemaConstants.CN_AT, principalEntry.getCommonName() );
091
092        EncryptionKey encryptionKey = principalEntry.getKeyMap().get( EncryptionType.DES_CBC_MD5 );
093
094        ByteBuffer buffer = ByteBuffer.allocate( encryptionKey.computeLength() );
095        outAttrs.add( KerberosAttribute.KRB5_KEY_AT, encryptionKey.encode( buffer ).array() );
096
097        int keyVersion = encryptionKey.getKeyVersion();
098
099        outAttrs.add( KerberosAttribute.KRB5_PRINCIPAL_NAME_AT, principalEntry.getPrincipal().toString() );
100        outAttrs.add( KerberosAttribute.KRB5_KEY_VERSION_NUMBER_AT, Integer.toString( keyVersion ) );
101
102        return outAttrs;
103    }
104
105
106    /**
107     * Constructs a filter expression tree for the filter used to search the 
108     * directory.
109     * 
110     * @param schemaManager The server schemaManager to use for attribute lookups
111     * @param principal the principal to use for building the filter
112     * @return the filter expression tree
113     * @throws Exception if there are problems while looking up attributes
114     */
115    private static ExprNode getFilter( SchemaManager schemaManager, String principal ) throws Exception
116    {
117        AttributeType type = schemaManager.lookupAttributeTypeRegistry( KerberosAttribute.KRB5_PRINCIPAL_NAME_AT );
118        Value value = new Value( type, principal );
119
120        return new EqualityNode<String>( type, value );
121    }
122
123
124    /**
125     * Finds the Entry associated with the Kerberos principal name.
126     *
127     * @param session the session to use for the search
128     * @param searchBaseDn the base to use while searching
129     * @param principal the name of the principal to search for
130     * @return the server entry for the principal or null if non-existent
131     * @throws Exception if there are problems while searching the directory
132     */
133    public static Entry findPrincipalEntry( CoreSession session, Dn searchBaseDn, String principal )
134        throws Exception
135    {
136        Cursor<Entry> cursor = null;
137
138        try
139        {
140            SchemaManager schemaManager = session.getDirectoryService().getSchemaManager();
141            cursor = session
142                .search( searchBaseDn, SearchScope.SUBTREE,
143                    getFilter( schemaManager, principal ), AliasDerefMode.DEREF_ALWAYS,
144                    SchemaConstants.ALL_USER_ATTRIBUTES );
145
146            cursor.beforeFirst();
147
148            if ( cursor.next() )
149            {
150                Entry entry = cursor.get();
151                LOG.debug( "Found entry {} for kerberos principal name {}", entry.getDn(), principal );
152                LOG_KRB.debug( "Found entry {} for kerberos principal name {}", entry.getDn(), principal );
153
154                while ( cursor.next() )
155                {
156                    LOG.error( I18n.err( I18n.ERR_149, principal, cursor.next() ) );
157                }
158
159                return entry;
160            }
161            else
162            {
163                LOG.warn( "No server entry found for kerberos principal name {}", principal );
164                LOG_KRB.warn( "No server entry found for kerberos principal name {}", principal );
165
166                return null;
167            }
168        }
169        finally
170        {
171            if ( cursor != null )
172            {
173                cursor.close();
174            }
175        }
176    }
177}