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