View Javadoc

1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.server.kerberos.sam;
21  
22  
23  import java.util.HashMap;
24  import java.util.Hashtable;
25  import java.util.Map;
26  
27  import javax.naming.NamingException;
28  import javax.naming.directory.DirContext;
29  import javax.security.auth.kerberos.KerberosKey;
30  
31  import org.apache.directory.server.kerberos.shared.messages.value.SamType;
32  import org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntry;
33  
34  
35  /**
36   * The Subsystem that enables the Kerberos server to use plugable Single-use
37   * Authentication mechanisms.
38   *
39   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
40   * @version $Rev: 541569 $
41   */
42  public final class SamSubsystem
43  {
44      /** the property key base used for SAM algorithm verifiers */
45      public static final String PROPKEY_BASE = "kerberos.sam.type.";
46  
47      /** the SAM subsystem instance */
48      public static SamSubsystem instance;
49  
50      /** a map of verifiers so we do not need to create a new one every time */
51      private final Map<SamType, SamVerifier> verifiers = new HashMap<SamType, SamVerifier>();
52  
53      /** the key integrity checker used by the subsystem for all sam types */
54      private KeyIntegrityChecker keyChecker;
55  
56      /** the user context the SamSubsystem would use to verify passwords */
57      private DirContext userContext;
58      private String userBaseRdn;
59  
60  
61      /**
62       * Gets the singleton instance of the SamSubsystem.
63       *
64       * @return the singleton for the SamSubsystem
65       */
66      public static SamSubsystem getInstance()
67      {
68          if ( instance == null )
69          {
70              instance = new SamSubsystem();
71          }
72  
73          return instance;
74      }
75  
76  
77      /**
78       * Sets the KeyIntegrityChecker used by the entire SamSubsystem.
79       *
80       * @param keyChecker the KeyIntegrityChecker used by the entire SamSubsystem
81       */
82      public void setIntegrityChecker( KeyIntegrityChecker keyChecker )
83      {
84          this.keyChecker = keyChecker;
85      }
86  
87  
88      /**
89       * Uses the principal entry information to load the approapriate SamVerifier
90       * and verify the Single-use password.
91       *
92       * @param entry the store entry for the Kerberos principal
93       * @param sad the single-use authentication data encrypted timestamp payload
94       * @return true if verification passed, false otherwise
95       * @throws SamException thrown when there is a failure within the verifier
96       * or a verifier cannot be found.
97       */
98      public KerberosKey verify( PrincipalStoreEntry entry, byte[] sad ) throws SamException
99      {
100         SamVerifier verifier = null;
101 
102         if ( keyChecker == null )
103         {
104             throw new IllegalStateException( "SamSubsystem not enabled with key integrity checker" );
105         }
106 
107         if ( entry.getSamType() == null )
108         {
109             throw new SamException( entry.getSamType(), "Entry has null SAM type" );
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 = "Could not find property '" + 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 = "Expecting entries with SAM type of " + verifier.getSamType();
164 
165                 msg += " but got a type of entry with SAM type of " + entry.getSamType();
166 
167                 throw new SamException( entry.getSamType(), msg );
168             }
169 
170             verifiers.put( verifier.getSamType(), verifier );
171 
172             return verifier.verify( entry.getPrincipal(), sad );
173         }
174         catch ( ClassNotFoundException e )
175         {
176             String msg = "Could not find verifier class '" + fqcn;
177 
178             msg += "' for SamType( " + entry.getSamType() + " ) ";
179 
180             throw new SamException( entry.getSamType(), msg, e );
181         }
182         catch ( IllegalAccessException e )
183         {
184             String msg = "No public default constructor on class '" + fqcn;
185 
186             msg += "' for SamType( " + entry.getSamType() + " ) ";
187 
188             throw new SamException( entry.getSamType(), msg, e );
189         }
190         catch ( InstantiationException e )
191         {
192             String msg = "Failed on default constructor invocation for class '" + fqcn;
193 
194             msg += "' for SamType( " + entry.getSamType() + " ) ";
195 
196             throw new SamException( entry.getSamType(), msg, e );
197         }
198     }
199 
200 
201     /**
202      * Sets the context under which user entries can be found.
203      *
204      * @param userContext the jndi context under which users can be found.
205      * @param userBaseRdn the container with users
206      */
207     public void setUserContext( DirContext userContext, String userBaseRdn )
208     {
209         this.userContext = userContext;
210         this.userBaseRdn = userBaseRdn;
211     }
212 }