[CXF-7429] Preventing NPE
[cxf.git] / rt / rs / security / sso / saml / src / main / java / org / apache / cxf / rs / security / saml / sso / AbstractSSOSpHandler.java
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 package org.apache.cxf.rs.security.saml.sso;
20
21 import java.io.IOException;
22 import java.util.Date;
23 import java.util.Properties;
24 import java.util.logging.Level;
25 import java.util.logging.Logger;
26
27 import javax.annotation.PreDestroy;
28 import javax.security.auth.callback.CallbackHandler;
29
30 import org.apache.cxf.common.logging.LogUtils;
31 import org.apache.cxf.jaxrs.utils.HttpUtils;
32 import org.apache.cxf.rs.security.saml.sso.state.SPStateManager;
33 import org.apache.cxf.rt.security.utils.SecurityUtils;
34 import org.apache.wss4j.common.crypto.Crypto;
35 import org.apache.wss4j.common.crypto.CryptoFactory;
36 import org.apache.wss4j.common.ext.WSSecurityException;
37 import org.apache.wss4j.common.saml.OpenSAMLUtil;
38
39 public class AbstractSSOSpHandler {
40 private static final Logger LOG =
41 LogUtils.getL7dLogger(AbstractSSOSpHandler.class);
42
43 private SPStateManager stateProvider;
44 private long stateTimeToLive = SSOConstants.DEFAULT_STATE_TIME;
45 private Crypto signatureCrypto;
46 private String signaturePropertiesFile;
47 private CallbackHandler callbackHandler;
48 private String callbackHandlerClass;
49 private String signatureUsername;
50
51 static {
52 OpenSAMLUtil.initSamlEngine();
53 }
54
55 @PreDestroy
56 public void close() {
57 if (stateProvider != null) {
58 try {
59 stateProvider.close();
60 } catch (IOException ex) {
61 LOG.warning("State provider can not be closed: " + ex.getMessage());
62 }
63 stateProvider = null;
64 }
65 }
66
67 public void setSignatureCrypto(Crypto crypto) {
68 signatureCrypto = crypto;
69 }
70
71 /**
72 * Set the String corresponding to the signature Properties class
73 * @param signaturePropertiesFile the String corresponding to the signature properties file
74 */
75 public void setSignaturePropertiesFile(String signaturePropertiesFile) {
76 this.signaturePropertiesFile = signaturePropertiesFile;
77 LOG.fine("Setting signature properties: " + signaturePropertiesFile);
78 }
79
80 /**
81 * Set the CallbackHandler object.
82 * @param callbackHandler the CallbackHandler object.
83 */
84 public void setCallbackHandler(CallbackHandler callbackHandler) {
85 this.callbackHandler = callbackHandler;
86 LOG.fine("Setting callbackHandler: " + callbackHandler);
87 }
88
89 /**
90 * Set the String corresponding to the CallbackHandler class.
91 * @param callbackHandlerClass the String corresponding to the CallbackHandler class.
92 */
93 public void setCallbackHandlerClass(String callbackHandlerClass) {
94 this.callbackHandlerClass = callbackHandlerClass;
95 LOG.fine("Setting callbackHandlerClass: " + callbackHandlerClass);
96 }
97
98 //TODO: support attaching a signature to the cookie value
99 protected String createCookie(String name,
100 String value,
101 String path,
102 String domain) {
103
104 String contextCookie = name + "=" + value;
105 // Setting a specific path restricts the browsers
106 // to return a cookie only to the web applications
107 // listening on that specific context path
108 if (path != null) {
109 contextCookie += ";Path=" + path;
110 }
111
112 // Setting a specific domain further restricts the browsers
113 // to return a cookie only to the web applications
114 // listening on the specific context path within a particular domain
115 if (domain != null) {
116 contextCookie += ";Domain=" + domain;
117 }
118
119 // Keep the cookie across the browser restarts until it actually expires.
120 // Note that the Expires property has been deprecated but apparently is
121 // supported better than 'max-age' property by different browsers
122 // (Firefox, IE, etc)
123 Date expiresDate = new Date(System.currentTimeMillis() + stateTimeToLive);
124 String cookieExpires = HttpUtils.getHttpDateFormat().format(expiresDate);
125 contextCookie += ";Expires=" + cookieExpires;
126 //TODO: Consider adding an 'HttpOnly' attribute
127
128 return contextCookie;
129 }
130
131 protected boolean isStateExpired(long stateCreatedAt, long expiresAt) {
132 Date currentTime = new Date();
133 if (currentTime.after(new Date(stateCreatedAt + getStateTimeToLive()))) {
134 return true;
135 }
136
137 return expiresAt > 0 && currentTime.after(new Date(expiresAt));
138 }
139
140 public void setStateProvider(SPStateManager stateProvider) {
141 this.stateProvider = stateProvider;
142 }
143
144 public SPStateManager getStateProvider() {
145 return stateProvider;
146 }
147
148 public void setStateTimeToLive(long stateTimeToLive) {
149 this.stateTimeToLive = stateTimeToLive;
150 }
151
152 public long getStateTimeToLive() {
153 return stateTimeToLive;
154 }
155
156 protected Crypto getSignatureCrypto() {
157 if (signatureCrypto == null && signaturePropertiesFile != null) {
158 Properties sigProperties = SecurityUtils.loadProperties(signaturePropertiesFile);
159 if (sigProperties == null) {
160 LOG.fine("Cannot load signature properties using: " + signaturePropertiesFile);
161 return null;
162 }
163 try {
164 signatureCrypto = CryptoFactory.getInstance(sigProperties);
165 } catch (WSSecurityException ex) {
166 LOG.fine("Error in loading the signature Crypto object: " + ex.getMessage());
167 return null;
168 }
169 }
170 return signatureCrypto;
171 }
172
173 protected CallbackHandler getCallbackHandler() {
174 if (callbackHandler == null && callbackHandlerClass != null) {
175 try {
176 callbackHandler = SecurityUtils.getCallbackHandler(callbackHandlerClass);
177 if (callbackHandler == null) {
178 LOG.fine("Cannot load CallbackHandler using: " + callbackHandlerClass);
179 return null;
180 }
181 } catch (Exception ex) {
182 LOG.log(Level.FINE, "Error in loading callback handler", ex);
183 return null;
184 }
185 }
186 return callbackHandler;
187 }
188
189 /**
190 * Set the username/alias to use to sign any request
191 * @param signatureUsername the username/alias to use to sign any request
192 */
193 public void setSignatureUsername(String signatureUsername) {
194 this.signatureUsername = signatureUsername;
195 LOG.fine("Setting signatureUsername: " + signatureUsername);
196 }
197
198 /**
199 * Get the username/alias to use to sign any request
200 * @return the username/alias to use to sign any request
201 */
202 public String getSignatureUsername() {
203 return signatureUsername;
204 }
205
206 }