cdc4b7276540a62831e20274f05181498af48bc3
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / serviceprovider / ShibHttpHook.java
1 /*
2  * Copyright [2005] [University Corporation for Advanced Internet Development, Inc.]
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /*
18  * ShibHttpHook - Receive callbacks from OpenSAML HTTP Session processing.
19  */
20 package edu.internet2.middleware.shibboleth.serviceprovider;
21
22 import java.net.HttpURLConnection;
23 import java.net.Socket;
24 import java.security.KeyManagementException;
25 import java.security.NoSuchAlgorithmException;
26 import java.security.Principal;
27 import java.security.PrivateKey;
28 import java.security.cert.CertificateException;
29 import java.security.cert.X509Certificate;
30
31 import javax.net.ssl.HttpsURLConnection;
32 import javax.net.ssl.KeyManager;
33 import javax.net.ssl.SSLContext;
34 import javax.net.ssl.SSLSocketFactory;
35 import javax.net.ssl.TrustManager;
36 import javax.net.ssl.X509KeyManager;
37 import javax.net.ssl.X509TrustManager;
38 import javax.servlet.http.HttpServletRequest;
39 import javax.servlet.http.HttpServletResponse;
40
41 import org.apache.log4j.Logger;
42 import org.opensaml.SAMLException;
43 import org.opensaml.SAMLSOAPHTTPBinding.HTTPHook;
44
45 import edu.internet2.middleware.shibboleth.common.Credential;
46 import edu.internet2.middleware.shibboleth.common.Credentials;
47 import edu.internet2.middleware.shibboleth.common.Trust;
48 import edu.internet2.middleware.shibboleth.metadata.AttributeAuthorityDescriptor;
49
50 /**
51  * A callback object added to the SAML Binding by Shib. During
52  * HTTP session establishment and Request/Response processing 
53  * to the AA, SAML calls these exists. This code traps HTTPS
54  * sessions and adds a JSSE TrustManager to process Certificates.
55  * 
56  * @author Howard Gilbert
57  *
58  */
59 public class ShibHttpHook implements HTTPHook {
60
61     private static Logger log = Logger.getLogger(HTTPHook.class);
62     
63     ServiceProviderContext context = ServiceProviderContext.getInstance();
64     ServiceProviderConfig config = context.getServiceProviderConfig();
65     Credentials credentials = config.getCredentials();
66     AttributeAuthorityDescriptor role;
67     Trust trust;
68     
69     /**
70      * @param role
71      */
72     public ShibHttpHook(AttributeAuthorityDescriptor role, Trust trust) {
73         super();
74         this.role = role;
75         this.trust = trust;
76     }
77
78     public boolean incoming(HttpServletRequest r, Object globalCtx,
79             Object callCtx) throws SAMLException {
80         // Not used
81         return true;
82     }
83
84     public boolean outgoing(HttpServletResponse r, Object globalCtx,
85             Object callCtx) throws SAMLException {
86         // Not used
87         return true;
88     }
89
90     public boolean incoming(HttpURLConnection conn, Object globalCtx,
91             Object callCtx) throws SAMLException {
92         // Not used
93         return true;
94     }
95
96     /**
97      * After the URLConnection has been initialized and before 
98      * the connect() method is called, this exit has a chance to
99      * do additional processing.
100      * 
101      * <p>If this is an HTTPS session, configure the SocketFactory
102      * to use a custom TrustManager for Certificate processing.</p>
103      */
104     public boolean outgoing(HttpURLConnection conn, Object globalCtx,
105             Object callCtx) throws SAMLException {
106         if (!(conn instanceof HttpsURLConnection)) {
107             return true; // http: sessions need no processing
108         }
109         HttpsURLConnection sslconn = (HttpsURLConnection) conn;
110         SSLContext sslContext = null;
111         try {
112             sslContext = SSLContext.getInstance("SSL");
113         } catch (NoSuchAlgorithmException e) {
114             log.error("Cannot find required SSL support");
115             return true;
116         }
117         TrustManager[] tms = new TrustManager[] {new ShibTrustManager()};
118         KeyManager[] kms = new KeyManager[] {new ShibKeyManager()};
119         try {
120             sslContext.init(kms,tms,new java.security.SecureRandom());
121         } catch (KeyManagementException e) {
122             return false;
123         }
124         SSLSocketFactory socketFactory = sslContext.getSocketFactory();
125         sslconn.setSSLSocketFactory(socketFactory);
126         return true;
127     }
128     
129     /**
130      * Called to select the Client Certificate the SP will present to 
131      * the AA.
132      * 
133      * <p>Normally a user KeyManager extends some class backed by a 
134      * KeyStore. It just chooses an alias, and lets the parent class 
135      * do the dirty work of extracting the Certificate chain from the 
136      * backing file. However, in Shibboleth the SP Credentials come
137      * from the configuration file and are in memory. There is no
138      * meaningful alias, so we make one up.
139      */
140     class ShibKeyManager implements X509KeyManager {
141         
142         public String fred ="Fred";
143         public String[] freds = {fred};
144
145         public String[] getClientAliases(String arg0, Principal[] arg1) {
146             return freds;
147         }
148
149         public String chooseClientAlias(String[] arg0, Principal[] arg1, Socket arg2) {
150             return fred;
151         }
152
153         public String[] getServerAliases(String arg0, Principal[] arg1) {
154             return freds;
155         }
156
157         public String chooseServerAlias(String arg0, Principal[] arg1, Socket arg2) {
158             return fred;
159         }
160
161         public X509Certificate[] getCertificateChain(String arg0) {
162             Credential credential = credentials.getCredential();
163             X509Certificate[] certificateChain = credential.getX509CertificateChain();
164             return certificateChain;
165         }
166
167         public PrivateKey getPrivateKey(String arg0) {
168             // TODO Get the SP Private Key from the Credentials object.
169             Credential credential = credentials.getCredential();
170             PrivateKey privateKey = credential.getPrivateKey();
171             return privateKey;
172         }
173         
174     }
175     
176     /**
177      * Called to approve or reject the Server Certificate of the AA.
178      */
179     class ShibTrustManager  implements X509TrustManager {
180
181         public X509Certificate[] getAcceptedIssuers() {
182             // Not needed, the Server has only one Certificate to send us.
183             return new X509Certificate[0]; 
184         }
185         
186         public void checkClientTrusted(X509Certificate[] arg0, String arg1) 
187             throws CertificateException {
188             // Not used, we are the client
189         }
190
191         public void checkServerTrusted(X509Certificate[] certs, String arg1) 
192             throws CertificateException {
193             if (trust.validate(certs[0],certs,role))
194                 return;
195             //throw new CertificateException("Cannot validate AA Server Certificate in Metadata");
196             
197         }
198         
199     }
200
201 }