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.sam;
021    
022    
023    import java.util.HashMap;
024    import java.util.Hashtable;
025    import java.util.Map;
026    
027    import javax.naming.NamingException;
028    import javax.naming.directory.DirContext;
029    import javax.security.auth.kerberos.KerberosKey;
030    
031    import org.apache.directory.server.i18n.I18n;
032    import org.apache.directory.server.kerberos.shared.messages.value.SamType;
033    import org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntry;
034    
035    
036    /**
037     * The Subsystem that enables the Kerberos server to use plugable Single-use
038     * Authentication mechanisms.
039     *
040     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
041     * @version $Rev: 902547 $
042     */
043    public final class SamSubsystem
044    {
045        /** the property key base used for SAM algorithm verifiers */
046        public static final String PROPKEY_BASE = "kerberos.sam.type.";
047    
048        /** the SAM subsystem instance */
049        public static SamSubsystem instance;
050    
051        /** a map of verifiers so we do not need to create a new one every time */
052        private final Map<SamType, SamVerifier> verifiers = new HashMap<SamType, SamVerifier>();
053    
054        /** the key integrity checker used by the subsystem for all sam types */
055        private KeyIntegrityChecker keyChecker;
056    
057        /** the user context the SamSubsystem would use to verify passwords */
058        private DirContext userContext;
059        private String userBaseRdn;
060    
061    
062        /**
063         * Gets the singleton instance of the SamSubsystem.
064         *
065         * @return the singleton for the SamSubsystem
066         */
067        public static SamSubsystem getInstance()
068        {
069            if ( instance == null )
070            {
071                instance = new SamSubsystem();
072            }
073    
074            return instance;
075        }
076    
077    
078        /**
079         * Sets the KeyIntegrityChecker used by the entire SamSubsystem.
080         *
081         * @param keyChecker the KeyIntegrityChecker used by the entire SamSubsystem
082         */
083        public void setIntegrityChecker( KeyIntegrityChecker keyChecker )
084        {
085            this.keyChecker = keyChecker;
086        }
087    
088    
089        /**
090         * Uses the principal entry information to load the approapriate SamVerifier
091         * and verify the Single-use password.
092         *
093         * @param entry the store entry for the Kerberos principal
094         * @param sad the single-use authentication data encrypted timestamp payload
095         * @return true if verification passed, false otherwise
096         * @throws SamException thrown when there is a failure within the verifier
097         * or a verifier cannot be found.
098         */
099        public KerberosKey verify( PrincipalStoreEntry entry, byte[] sad ) throws SamException
100        {
101            SamVerifier verifier = null;
102    
103            if ( keyChecker == null )
104            {
105                throw new IllegalStateException( I18n.err( I18n.ERR_651 ) );
106            }
107    
108            if ( entry.getSamType() == null )
109            {
110                throw new SamException( entry.getSamType(), I18n.err( I18n.ERR_652 ) );
111            }
112    
113            if ( verifiers.containsKey( entry.getSamType() ) )
114            {
115                verifier = verifiers.get( entry.getSamType() );
116    
117                return verifier.verify( entry.getPrincipal(), sad );
118            }
119    
120            String key = PROPKEY_BASE + entry.getSamType().getOrdinal();
121    
122            Hashtable<Object, Object> env = new Hashtable<Object, Object>();
123    
124            try
125            {
126                env.putAll( userContext.getEnvironment() );
127            }
128            catch ( NamingException e )
129            {
130                e.printStackTrace();
131            }
132    
133            if ( !env.containsKey( key ) )
134            {
135                String msg = I18n.err( I18n.ERR_653, key );
136    
137                throw new SamException( entry.getSamType(), msg );
138            }
139    
140            String fqcn = ( String ) env.get( key );
141    
142            try
143            {
144                Class c = Class.forName( fqcn );
145    
146                verifier = ( SamVerifier ) c.newInstance();
147    
148                try
149                {
150                    verifier.setUserContext( ( DirContext ) userContext.lookup( userBaseRdn ) );
151                }
152                catch ( NamingException e )
153                {
154                    e.printStackTrace();
155    
156                }
157    
158                verifier.setIntegrityChecker( keyChecker );
159    
160                verifier.startup();
161    
162                if ( !verifier.getSamType().equals( entry.getSamType() ) )
163                {
164                    String msg = I18n.err( I18n.ERR_654, verifier.getSamType(), entry.getSamType() );
165    
166                    throw new SamException( entry.getSamType(), msg );
167                }
168    
169                verifiers.put( verifier.getSamType(), verifier );
170    
171                return verifier.verify( entry.getPrincipal(), sad );
172            }
173            catch ( ClassNotFoundException e )
174            {
175                String msg = I18n.err( I18n.ERR_655, fqcn, entry.getSamType() );
176    
177                throw new SamException( entry.getSamType(), msg, e );
178            }
179            catch ( IllegalAccessException e )
180            {
181                String msg = I18n.err( I18n.ERR_656, fqcn, entry.getSamType() );
182    
183                throw new SamException( entry.getSamType(), msg, e );
184            }
185            catch ( InstantiationException e )
186            {
187                String msg = I18n.err( I18n.ERR_657, fqcn, entry.getSamType() );
188    
189                throw new SamException( entry.getSamType(), msg, e );
190            }
191        }
192    
193    
194        /**
195         * Sets the context under which user entries can be found.
196         *
197         * @param userContext the jndi context under which users can be found.
198         * @param userBaseRdn the container with users
199         */
200        public void setUserContext( DirContext userContext, String userBaseRdn )
201        {
202            this.userContext = userContext;
203            this.userBaseRdn = userBaseRdn;
204        }
205    }