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