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