Error handling for AQH creation.
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / hs / provider / CryptoHandleRepository.java
1 /* 
2  * The Shibboleth License, Version 1. 
3  * Copyright (c) 2002 
4  * University Corporation for Advanced Internet Development, Inc. 
5  * All rights reserved
6  * 
7  * 
8  * Redistribution and use in source and binary forms, with or without 
9  * modification, are permitted provided that the following conditions are met:
10  * 
11  * Redistributions of source code must retain the above copyright notice, this 
12  * list of conditions and the following disclaimer.
13  * 
14  * Redistributions in binary form must reproduce the above copyright notice, 
15  * this list of conditions and the following disclaimer in the documentation 
16  * and/or other materials provided with the distribution, if any, must include 
17  * the following acknowledgment: "This product includes software developed by 
18  * the University Corporation for Advanced Internet Development 
19  * <http://www.ucaid.edu>Internet2 Project. Alternately, this acknowledegement 
20  * may appear in the software itself, if and wherever such third-party 
21  * acknowledgments normally appear.
22  * 
23  * Neither the name of Shibboleth nor the names of its contributors, nor 
24  * Internet2, nor the University Corporation for Advanced Internet Development, 
25  * Inc., nor UCAID may be used to endorse or promote products derived from this 
26  * software without specific prior written permission. For written permission, 
27  * please contact shibboleth@shibboleth.org
28  * 
29  * Products derived from this software may not be called Shibboleth, Internet2, 
30  * UCAID, or the University Corporation for Advanced Internet Development, nor 
31  * may Shibboleth appear in their name, without prior written permission of the 
32  * University Corporation for Advanced Internet Development.
33  * 
34  * 
35  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
36  * AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
37  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
38  * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK 
39  * OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE. 
40  * IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY 
41  * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT, 
42  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
43  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
44  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
46  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
47  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48  */
49
50 package edu.internet2.middleware.shibboleth.hs.provider;
51
52 import java.io.ByteArrayInputStream;
53 import java.io.ByteArrayOutputStream;
54 import java.io.FileInputStream;
55 import java.io.IOException;
56 import java.io.ObjectInputStream;
57 import java.io.ObjectOutput;
58 import java.io.ObjectOutputStream;
59 import java.security.GeneralSecurityException;
60 import java.security.KeyException;
61 import java.security.KeyStore;
62 import java.security.KeyStoreException;
63 import java.security.NoSuchAlgorithmException;
64 import java.security.UnrecoverableKeyException;
65 import java.security.cert.CertificateException;
66 import java.util.Properties;
67 import java.util.zip.GZIPInputStream;
68 import java.util.zip.GZIPOutputStream;
69
70 import javax.crypto.Cipher;
71 import javax.crypto.SecretKey;
72
73 import org.apache.log4j.Logger;
74 import sun.misc.BASE64Decoder;
75 import sun.misc.BASE64Encoder;
76
77 import edu.internet2.middleware.shibboleth.common.AuthNPrincipal;
78 import edu.internet2.middleware.shibboleth.hs.HandleRepository;
79 import edu.internet2.middleware.shibboleth.hs.HandleRepositoryException;
80
81 /**
82  * <code>HandleRepository</code> implementation that employs the use of a shard secret
83  * in order to transmit identity information.
84  * 
85  * @author Walter Hoehn (wassa@columbia.edu)
86  */
87 public class CryptoHandleRepository extends BaseHandleRepository implements HandleRepository {
88
89         private static Logger log = Logger.getLogger(CryptoHandleRepository.class.getName());
90         protected SecretKey secret;
91
92         public CryptoHandleRepository(Properties properties) throws HandleRepositoryException {
93                 super(properties);
94                 try {
95                         KeyStore keyStore = KeyStore.getInstance("JCEKS");
96
97                         keyStore.load(
98                                 new FileInputStream(
99                                         properties.getProperty(
100                                                 "edu.internet2.middleware.shibboleth.hs.provider.CryptoHandleRepository.keyStorePath")),
101                                 properties
102                                         .getProperty("edu.internet2.middleware.shibboleth.hs.provider.CryptoHandleRepository.keyStorePassword")
103                                         .toCharArray());
104                         secret =
105                                 (SecretKey) keyStore.getKey(
106                                         properties.getProperty(
107                                                 "edu.internet2.middleware.shibboleth.hs.provider.CryptoHandleRepository.keyStoreKeyAlias"),
108                                         properties
109                                                 .getProperty("edu.internet2.middleware.shibboleth.hs.provider.CryptoHandleRepository.keyStoreKeyPassword")
110                                                 .toCharArray());
111
112                 } catch (KeyStoreException e) {
113                         log.error(
114                                 "An error occurred while loading the java keystore.  Unable to initialize Crypto Handle Repository: "
115                                         + e);
116                         throw new HandleRepositoryException("An error occurred while loading the java keystore.  Unable to initialize Crypto Handle Repository.");
117                 } catch (CertificateException e) {
118                         log.error(
119                                 "The java keystore contained corrupted data.  Unable to initialize Crypto Handle Repository: " + e);
120                         throw new HandleRepositoryException("The java keystore contained corrupted data.  Unable to initialize Crypto Handle Repository.");
121                 } catch (NoSuchAlgorithmException e) {
122                         log.error(
123                                 "Appropriate JCE provider not found in the java environment. Unable to initialize Crypto Handle Repository: "
124                                         + e);
125                         throw new HandleRepositoryException("Appropriate JCE provider not found in the java environment. Unable to initialize Crypto Handle Repository.");
126                 } catch (IOException e) {
127                         log.error(
128                                 "An error accessing while loading the java keystore.  Unable to initialize Crypto Handle Repository: "
129                                         + e);
130                         throw new HandleRepositoryException("An error occurred while accessing the java keystore.  Unable to initialize Crypto Handle Repository.");
131                 } catch (UnrecoverableKeyException e) {
132                         log.error(
133                                 "Secret could not be loaded from the java keystore.  Verify that the alias and password are correct: "
134                                         + e);
135                         throw new HandleRepositoryException("Secret could not be loaded from the java keystore.  Verify that the alias and password are correct. ");
136                 }
137         }
138
139         /**
140          * @see edu.internet2.middleware.shibboleth.hs.HandleRepository#getHandle(Principal)
141          */
142         public String getHandle(AuthNPrincipal principal) throws HandleRepositoryException {
143                 try {
144                         if (principal == null) {
145                                 log.error("A principal must be supplied for Attribute Query Handle creation.");
146                                 throw new IllegalArgumentException("A principal must be supplied for Attribute Query Handle creation.");
147                         }
148
149                         HandleEntry handleEntry = createHandleEntry(principal);
150                         ByteArrayOutputStream outStream = new ByteArrayOutputStream();
151                         GZIPOutputStream zipStream = new GZIPOutputStream(outStream);
152                         ObjectOutput objectStream = new ObjectOutputStream(zipStream);
153                         objectStream.writeObject(handleEntry);
154                         objectStream.flush();
155                         objectStream.close();
156
157                         Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
158                         cipher.init(Cipher.ENCRYPT_MODE, secret);
159                         byte[] cipherTextHandle = cipher.doFinal(outStream.toByteArray());
160
161                         String handle = new BASE64Encoder().encode(cipherTextHandle);
162                         return handle.replaceAll(System.getProperty("line.separator"), "");
163
164                 } catch (KeyException e) {
165                         log.error("Could not use the supplied secret key for Triple DES encryption: " + e);
166                         throw new HandleRepositoryException("Could not use the supplied secret key for Triple DES encryption.");
167                 } catch (GeneralSecurityException e) {
168                         log.error("Appropriate JCE provider not found in the java environment.  Could not load Cipher: " + e);
169                         throw new HandleRepositoryException("Appropriate JCE provider not found in the java environment.  Could not load Cipher.");
170                 } catch (IOException e) {
171                         log.error("Could not serialize Principal for handle creation: " + e);
172                         throw new HandleRepositoryException("Could not serialize Principal for Attribute Query Handle creation.");
173                 }
174         }
175
176         /**
177          * @see edu.internet2.middleware.shibboleth.hs.HandleRepository#getPrincipal(String)
178          */
179         public AuthNPrincipal getPrincipal(String handle) {
180
181                 try {
182                         Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
183                         cipher.init(Cipher.DECRYPT_MODE, secret);
184                         byte[] objectArray = cipher.doFinal(new BASE64Decoder().decodeBuffer(handle));
185
186                         ObjectInputStream objectStream =
187                                 new ObjectInputStream(new GZIPInputStream(new ByteArrayInputStream(objectArray)));
188                         HandleEntry handleEntry = (HandleEntry) objectStream.readObject();
189                         return handleEntry.principal;
190
191                 } catch (Exception e) {
192                         System.err.println(e);
193                         return null;
194                 }
195         }
196
197 }