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     */
020    package org.apache.directory.server.kerberos.shared.store.operations;
021    
022    import org.apache.directory.server.core.CoreSession;
023    import org.apache.directory.server.core.filtering.EntryFilteringCursor;
024    import org.apache.directory.server.i18n.I18n;
025    import org.apache.directory.server.kerberos.shared.crypto.encryption.EncryptionType;
026    import org.apache.directory.server.kerberos.shared.io.encoder.EncryptionKeyEncoder;
027    import org.apache.directory.server.kerberos.shared.messages.value.EncryptionKey;
028    import org.apache.directory.server.kerberos.shared.store.KerberosAttribute;
029    import org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntry;
030    import org.apache.directory.shared.ldap.constants.SchemaConstants;
031    import org.apache.directory.shared.ldap.entry.StringValue;
032    import org.apache.directory.shared.ldap.entry.ServerEntry;
033    import org.apache.directory.shared.ldap.entry.Value;
034    import org.apache.directory.shared.ldap.filter.EqualityNode;
035    import org.apache.directory.shared.ldap.filter.ExprNode;
036    import org.apache.directory.shared.ldap.filter.SearchScope;
037    import org.apache.directory.shared.ldap.message.AliasDerefMode;
038    import org.apache.directory.shared.ldap.name.DN;
039    import org.apache.directory.shared.ldap.schema.AttributeType;
040    import org.apache.directory.shared.ldap.schema.SchemaManager;
041    import org.slf4j.Logger;
042    import org.slf4j.LoggerFactory;
043    
044    
045    /**
046     * Commonly used store utility operations.
047     *
048     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
049     * @version $Rev$, $Date$
050     */
051    public class StoreUtils
052    {
053        private static final Logger LOG = LoggerFactory.getLogger( StoreUtils.class );
054        
055        
056        /**
057         * Creates a ServerEntry for a PrincipalStoreEntry, doing what a state 
058         * factory does but for ServerEntry instead of Attributes.
059         *
060         * @param session the session to use to access the directory's registries
061         * @param dn the distinguished name of the principal to be 
062         * @param principalEntry the principal entry to convert into a ServerEntry
063         * @return the resultant server entry for the PrincipalStoreEntry argument
064         * @throws Exception if there are problems accessing registries
065         */
066        public static ServerEntry toServerEntry( CoreSession session, DN dn, PrincipalStoreEntry principalEntry ) 
067            throws Exception
068        {
069            ServerEntry outAttrs = session.getDirectoryService().newEntry( dn );
070            
071            // process the objectClass attribute
072            outAttrs.add( SchemaConstants.OBJECT_CLASS_AT, 
073                SchemaConstants.TOP_OC, SchemaConstants.UID_OBJECT_AT, 
074                "uidObject", SchemaConstants.EXTENSIBLE_OBJECT_OC, 
075                SchemaConstants.PERSON_OC, SchemaConstants.ORGANIZATIONAL_PERSON_OC,
076                SchemaConstants.INET_ORG_PERSON_OC, SchemaConstants.KRB5_PRINCIPAL_OC,
077                "krb5KDCEntry" );
078    
079            outAttrs.add( SchemaConstants.UID_AT, principalEntry.getUserId() );
080            outAttrs.add( KerberosAttribute.APACHE_SAM_TYPE_AT, "7" );
081            outAttrs.add( SchemaConstants.SN_AT, principalEntry.getUserId() );
082            outAttrs.add( SchemaConstants.CN_AT, principalEntry.getCommonName() );
083            
084            EncryptionKey encryptionKey = principalEntry.getKeyMap().get( EncryptionType.DES_CBC_MD5 );
085            outAttrs.add( KerberosAttribute.KRB5_KEY_AT, EncryptionKeyEncoder.encode( encryptionKey ) );
086    
087            int keyVersion = encryptionKey.getKeyVersion();
088    
089            outAttrs.add( KerberosAttribute.KRB5_PRINCIPAL_NAME_AT, principalEntry.getPrincipal().getName() );
090            outAttrs.add( KerberosAttribute.KRB5_KEY_VERSION_NUMBER_AT, Integer.toString( keyVersion ) );
091    
092            return outAttrs;
093        }
094        
095        
096        /**
097         * Constructs a filter expression tree for the filter used to search the 
098         * directory.
099         * 
100         * @param registry the registry to use for attribute lookups
101         * @param principal the principal to use for building the filter
102         * @return the filter expression tree
103         * @throws Exception if there are problems while looking up attributes
104         */
105        private static ExprNode getFilter( SchemaManager schemaManager, String principal ) throws Exception
106        {
107            AttributeType type = schemaManager.lookupAttributeTypeRegistry( KerberosAttribute.KRB5_PRINCIPAL_NAME_AT );
108            Value<String> value = new StringValue( type, principal );
109            return new EqualityNode<String>( KerberosAttribute.KRB5_PRINCIPAL_NAME_AT, value );
110        }
111        
112    
113        /**
114         * Finds the ServerEntry associated with the Kerberos principal name.
115         *
116         * @param session the session to use for the search
117         * @param searchBaseDn the base to use while searching
118         * @param principal the name of the principal to search for
119         * @return the server entry for the principal or null if non-existent
120         * @throws Exception if there are problems while searching the directory
121         */
122        public static ServerEntry findPrincipalEntry( CoreSession session, DN searchBaseDn, String principal ) 
123            throws Exception
124        {
125            EntryFilteringCursor cursor = null;
126            
127            try
128            {
129                SchemaManager schemaManager = session.getDirectoryService().getSchemaManager();
130                cursor = session.search( searchBaseDn, SearchScope.SUBTREE, 
131                    getFilter( schemaManager, principal ), AliasDerefMode.DEREF_ALWAYS, null );
132        
133                cursor.beforeFirst();
134                if ( cursor.next() )
135                {
136                    ServerEntry entry = cursor.get();
137                    LOG.debug( "Found entry {} for kerberos principal name {}", entry, principal );
138                    
139                    while ( cursor.next() )
140                    {
141                        LOG.error( I18n.err( I18n.ERR_149, principal, cursor.next() ) );
142                    }
143                    
144                    return entry;
145                }
146                else
147                {
148                    LOG.warn( "No server entry found for kerberos principal name {}", principal );
149                    return null;
150                }
151            }
152            finally
153            {
154                if ( cursor != null )
155                {
156                    cursor.close();
157                }
158            }
159        }
160    }