You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by co...@apache.org on 2012/05/17 16:12:07 UTC
svn commit: r1339609 -
/cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/
Author: coheigea
Date: Thu May 17 14:12:06 2012
New Revision: 1339609
URL: http://svn.apache.org/viewvc?rev=1339609&view=rev
Log:
Added support for signing AuthnRequests using the redirect binding
Modified:
cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/AbstractSSOSpHandler.java
cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/AbstractServiceProviderFilter.java
cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/RequestAssertionConsumerService.java
cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SSOConstants.java
cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SamlRedirectBindingFilter.java
Modified: cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/AbstractSSOSpHandler.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/AbstractSSOSpHandler.java?rev=1339609&r1=1339608&r2=1339609&view=diff
==============================================================================
--- cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/AbstractSSOSpHandler.java (original)
+++ cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/AbstractSSOSpHandler.java Thu May 17 14:12:06 2012
@@ -18,20 +18,70 @@
*/
package org.apache.cxf.rs.security.saml.sso;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
import java.util.Date;
+import java.util.Properties;
+import java.util.logging.Logger;
+import javax.security.auth.callback.CallbackHandler;
+
+import org.apache.cxf.common.classloader.ClassLoaderUtils;
+import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.jaxrs.utils.HttpUtils;
import org.apache.cxf.rs.security.saml.sso.state.SPStateManager;
+import org.apache.ws.security.WSSecurityException;
+import org.apache.ws.security.components.crypto.Crypto;
+import org.apache.ws.security.components.crypto.CryptoFactory;
import org.apache.ws.security.saml.ext.OpenSAMLUtil;
public class AbstractSSOSpHandler {
+ private static final Logger LOG =
+ LogUtils.getL7dLogger(AbstractSSOSpHandler.class);
+
private SPStateManager stateProvider;
private long stateTimeToLive = SSOConstants.DEFAULT_STATE_TIME;
+ private Crypto signatureCrypto;
+ private String signaturePropertiesFile;
+ private CallbackHandler callbackHandler;
+ private String callbackHandlerClass;
static {
OpenSAMLUtil.initSamlEngine();
}
+ public void setSignatureCrypto(Crypto crypto) {
+ signatureCrypto = crypto;
+ }
+
+ /**
+ * Set the String corresponding to the signature Properties class
+ * @param signaturePropertiesFile the String corresponding to the signature properties file
+ */
+ public void setSignaturePropertiesFile(String signaturePropertiesFile) {
+ this.signaturePropertiesFile = signaturePropertiesFile;
+ LOG.fine("Setting signature properties: " + signaturePropertiesFile);
+ }
+
+ /**
+ * Set the CallbackHandler object.
+ * @param callbackHandler the CallbackHandler object.
+ */
+ public void setCallbackHandler(CallbackHandler callbackHandler) {
+ this.callbackHandler = callbackHandler;
+ LOG.fine("Setting callbackHandler: " + callbackHandler);
+ }
+
+ /**
+ * Set the String corresponding to the CallbackHandler class.
+ * @param callbackHandlerClass the String corresponding to the CallbackHandler class.
+ */
+ public void setCallbackHandlerClass(String callbackHandlerClass) {
+ this.callbackHandlerClass = callbackHandlerClass;
+ LOG.fine("Setting callbackHandlerClass: " + callbackHandlerClass);
+ }
+
//TODO: support attaching a signature to the cookie value
protected String createCookie(String name,
String value,
@@ -93,4 +143,83 @@ public class AbstractSSOSpHandler {
public long getStateTimeToLive() {
return stateTimeToLive;
}
+
+ protected static Properties getProps(Object o) {
+ Properties properties = null;
+ if (o instanceof Properties) {
+ properties = (Properties)o;
+ } else if (o instanceof String) {
+ URL url = null;
+ try {
+ url = ClassLoaderUtils.getResource((String)o, AbstractSSOSpHandler.class);
+ if (url == null) {
+ url = new URL((String)o);
+ }
+ if (url != null) {
+ properties = new Properties();
+ InputStream ins = url.openStream();
+ properties.load(ins);
+ ins.close();
+ }
+ } catch (IOException e) {
+ LOG.fine(e.getMessage());
+ properties = null;
+ }
+ } else if (o instanceof URL) {
+ properties = new Properties();
+ try {
+ InputStream ins = ((URL)o).openStream();
+ properties.load(ins);
+ ins.close();
+ } catch (IOException e) {
+ LOG.fine(e.getMessage());
+ properties = null;
+ }
+ }
+ return properties;
+ }
+
+ protected Crypto getSignatureCrypto() {
+ if (signatureCrypto == null && signaturePropertiesFile != null) {
+ Properties sigProperties = getProps(signaturePropertiesFile);
+ if (sigProperties == null) {
+ LOG.fine("Cannot load signature properties using: " + signaturePropertiesFile);
+ return null;
+ }
+ try {
+ signatureCrypto = CryptoFactory.getInstance(sigProperties);
+ } catch (WSSecurityException ex) {
+ LOG.fine("Error in loading the signature Crypto object: " + ex.getMessage());
+ return null;
+ }
+ }
+ return signatureCrypto;
+ }
+
+ protected CallbackHandler getCallbackHandler() {
+ if (callbackHandler == null && callbackHandlerClass != null) {
+ callbackHandler = getCallbackHandler(callbackHandlerClass);
+ if (callbackHandler == null) {
+ LOG.fine("Cannot load CallbackHandler using: " + callbackHandlerClass);
+ return null;
+ }
+ }
+ return callbackHandler;
+ }
+
+ private CallbackHandler getCallbackHandler(Object o) {
+ CallbackHandler handler = null;
+ if (o instanceof CallbackHandler) {
+ handler = (CallbackHandler)o;
+ } else if (o instanceof String) {
+ try {
+ handler =
+ (CallbackHandler)ClassLoaderUtils.loadClass((String)o, this.getClass()).newInstance();
+ } catch (Exception e) {
+ LOG.fine(e.getMessage());
+ handler = null;
+ }
+ }
+ return handler;
+ }
}
Modified: cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/AbstractServiceProviderFilter.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/AbstractServiceProviderFilter.java?rev=1339609&r1=1339608&r2=1339609&view=diff
==============================================================================
--- cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/AbstractServiceProviderFilter.java (original)
+++ cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/AbstractServiceProviderFilter.java Thu May 17 14:12:06 2012
@@ -63,6 +63,16 @@ public abstract class AbstractServicePro
private String assertionConsumerServiceAddress;
private String webAppDomain;
private AuthnRequestBuilder authnRequestBuilder = new DefaultAuthnRequestBuilder();
+ private boolean signRequest;
+ private String signatureUsername;
+
+ public void setSignRequest(boolean signRequest) {
+ this.signRequest = signRequest;
+ }
+
+ public boolean isSignRequest() {
+ return signRequest;
+ }
public void setAuthnRequestBuilder(AuthnRequestBuilder authnRequestBuilder) {
this.authnRequestBuilder = authnRequestBuilder;
@@ -84,7 +94,24 @@ public abstract class AbstractServicePro
public String getIdpServiceAddress() {
return idpServiceAddress;
}
-
+
+ /**
+ * Set the username/alias to use to sign any request
+ * @param signatureUsername the username/alias to use to sign any request
+ */
+ public void setSignatureUsername(String signatureUsername) {
+ this.signatureUsername = signatureUsername;
+ LOG.fine("Setting signatureUsername: " + signatureUsername);
+ }
+
+ /**
+ * Get the username/alias to use to sign any request
+ * @return the username/alias to use to sign any request
+ */
+ public String getSignatureUsername() {
+ return signatureUsername;
+ }
+
private String getIssuerId(Message m) {
if (issuerId == null) {
return new UriInfoImpl(m).getBaseUri().toString();
Modified: cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/RequestAssertionConsumerService.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/RequestAssertionConsumerService.java?rev=1339609&r1=1339608&r2=1339609&view=diff
==============================================================================
--- cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/RequestAssertionConsumerService.java (original)
+++ cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/RequestAssertionConsumerService.java Thu May 17 14:12:06 2012
@@ -19,15 +19,12 @@
package org.apache.cxf.rs.security.saml.sso;
import java.io.ByteArrayInputStream;
-import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URI;
-import java.net.URL;
import java.net.URLDecoder;
import java.util.Date;
-import java.util.Properties;
import java.util.ResourceBundle;
import java.util.UUID;
import java.util.logging.Logger;
@@ -47,7 +44,6 @@ import javax.ws.rs.core.Response;
import org.w3c.dom.Document;
-import org.apache.cxf.common.classloader.ClassLoaderUtils;
import org.apache.cxf.common.i18n.BundleUtils;
import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.common.util.Base64Exception;
@@ -61,8 +57,6 @@ import org.apache.cxf.rs.security.saml.s
import org.apache.cxf.rs.security.saml.sso.state.ResponseState;
import org.apache.cxf.transport.http.AbstractHTTPDestination;
import org.apache.ws.security.WSSecurityException;
-import org.apache.ws.security.components.crypto.Crypto;
-import org.apache.ws.security.components.crypto.CryptoFactory;
import org.apache.ws.security.saml.ext.OpenSAMLUtil;
import org.opensaml.xml.XMLObject;
@@ -75,8 +69,6 @@ public class RequestAssertionConsumerSer
private boolean supportDeflateEncoding = true;
private boolean supportBase64Encoding = true;
- private Crypto signatureCrypto;
- private String signaturePropertiesFile;
private boolean enforceAssertionsSigned = true;
@Context
@@ -103,19 +95,6 @@ public class RequestAssertionConsumerSer
return supportBase64Encoding;
}
- public void setSignatureCrypto(Crypto crypto) {
- signatureCrypto = crypto;
- }
-
- /**
- * Set the String corresponding to the signature Properties class
- * @param signaturePropertiesFile the String corresponding to the signature properties file
- */
- public void setSignaturePropertiesFile(String signaturePropertiesFile) {
- this.signaturePropertiesFile = signaturePropertiesFile;
- LOG.fine("Setting signature properties: " + signaturePropertiesFile);
- }
-
@POST
@Produces(MediaType.APPLICATION_FORM_URLENCODED)
public Response processSamlResponse(@FormParam(SSOConstants.SAML_RESPONSE) String encodedSamlResponse,
@@ -330,56 +309,4 @@ public class RequestAssertionConsumerSer
LOG.warning(errorMsg.toString());
}
- private Crypto getSignatureCrypto() {
- if (signatureCrypto == null && signaturePropertiesFile != null) {
- Properties sigProperties = getProps(signaturePropertiesFile);
- if (sigProperties == null) {
- LOG.fine("Cannot load signature properties using: " + signaturePropertiesFile);
- return null;
- }
- try {
- signatureCrypto = CryptoFactory.getInstance(sigProperties);
- } catch (WSSecurityException ex) {
- LOG.fine("Error in loading the signature Crypto object: " + ex.getMessage());
- return null;
- }
- }
- return signatureCrypto;
- }
-
- private static Properties getProps(Object o) {
- Properties properties = null;
- if (o instanceof Properties) {
- properties = (Properties)o;
- } else if (o instanceof String) {
- URL url = null;
- try {
- url = ClassLoaderUtils.getResource((String)o, RequestAssertionConsumerService.class);
- if (url == null) {
- url = new URL((String)o);
- }
- if (url != null) {
- properties = new Properties();
- InputStream ins = url.openStream();
- properties.load(ins);
- ins.close();
- }
- } catch (IOException e) {
- LOG.fine(e.getMessage());
- properties = null;
- }
- } else if (o instanceof URL) {
- properties = new Properties();
- try {
- InputStream ins = ((URL)o).openStream();
- properties.load(ins);
- ins.close();
- } catch (IOException e) {
- LOG.fine(e.getMessage());
- properties = null;
- }
- }
- return properties;
- }
-
}
Modified: cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SSOConstants.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SSOConstants.java?rev=1339609&r1=1339608&r2=1339609&view=diff
==============================================================================
--- cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SSOConstants.java (original)
+++ cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SSOConstants.java Thu May 17 14:12:06 2012
@@ -18,13 +18,20 @@
*/
package org.apache.cxf.rs.security.saml.sso;
+import org.apache.ws.security.WSConstants;
+
public final class SSOConstants {
public static final String SAML_REQUEST = "SAMLRequest";
public static final String SAML_RESPONSE = "SAMLResponse";
public static final String RELAY_STATE = "RelayState";
+ public static final String SIG_ALG = "SigAlg";
+ public static final String SIGNATURE = "Signature";
public static final String SECURITY_CONTEXT_TOKEN = "org.apache.cxf.websso.context";
public static final long DEFAULT_STATE_TIME = 2L * 60L * 1000L;
+ public static final String RSA_SHA1 = WSConstants.RSA_SHA1;
+ public static final String DSA_SHA1 = WSConstants.DSA;
+
private SSOConstants() {
}
Modified: cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SamlRedirectBindingFilter.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SamlRedirectBindingFilter.java?rev=1339609&r1=1339608&r2=1339609&view=diff
==============================================================================
--- cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SamlRedirectBindingFilter.java (original)
+++ cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SamlRedirectBindingFilter.java Thu May 17 14:12:06 2012
@@ -18,6 +18,12 @@
*/
package org.apache.cxf.rs.security.saml.sso;
+import java.net.URLEncoder;
+import java.security.PrivateKey;
+import java.security.Signature;
+import java.security.cert.X509Certificate;
+
+import javax.security.auth.callback.CallbackHandler;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
@@ -25,6 +31,11 @@ import javax.ws.rs.core.UriBuilder;
import org.apache.cxf.jaxrs.model.ClassResourceInfo;
import org.apache.cxf.message.Message;
+import org.apache.ws.security.WSPasswordCallback;
+import org.apache.ws.security.WSSecurityException;
+import org.apache.ws.security.components.crypto.Crypto;
+import org.apache.ws.security.components.crypto.CryptoType;
+import org.apache.ws.security.util.Base64;
public class SamlRedirectBindingFilter extends AbstractServiceProviderFilter {
@@ -36,7 +47,10 @@ public class SamlRedirectBindingFilter e
SamlRequestInfo info = createSamlRequestInfo(m);
UriBuilder ub = UriBuilder.fromUri(getIdpServiceAddress());
ub.queryParam(SSOConstants.SAML_REQUEST, info.getEncodedSamlRequest());
- ub.queryParam(SSOConstants.RELAY_STATE, info.getRelayState());
+ ub.queryParam(SSOConstants.RELAY_STATE, info.getRelayState());
+ if (isSignRequest()) {
+ signRequest(ub);
+ }
String contextCookie = createCookie(SSOConstants.RELAY_STATE,
info.getRelayState(),
@@ -49,10 +63,75 @@ public class SamlRedirectBindingFilter e
.header("Set-Cookie", contextCookie)
.build();
} catch (Exception ex) {
+ ex.printStackTrace();
throw new WebApplicationException(ex);
}
}
}
+ /**
+ * Sign a request according to the redirect binding spec for Web SSO
+ */
+ private void signRequest(UriBuilder ub) throws Exception {
+ Crypto crypto = getSignatureCrypto();
+ if (crypto == null) {
+ LOG.fine("No crypto instance of properties file configured for signature");
+ throw new WebApplicationException();
+ }
+ String signatureUser = getSignatureUsername();
+ if (signatureUser == null) {
+ LOG.fine("No user configured for signature");
+ throw new WebApplicationException();
+ }
+ CallbackHandler callbackHandler = getCallbackHandler();
+ if (callbackHandler == null) {
+ LOG.fine("No CallbackHandler configured to supply a password for signature");
+ throw new WebApplicationException();
+ }
+
+ CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS);
+ cryptoType.setAlias(signatureUser);
+ X509Certificate[] issuerCerts = crypto.getX509Certificates(cryptoType);
+ if (issuerCerts == null) {
+ throw new WSSecurityException(
+ "No issuer certs were found to sign the request using name: " + signatureUser
+ );
+ }
+
+ String sigAlgo = SSOConstants.RSA_SHA1;
+ String pubKeyAlgo = issuerCerts[0].getPublicKey().getAlgorithm();
+ String jceSigAlgo = "SHA1withRSA";
+ LOG.fine("automatic sig algo detection: " + pubKeyAlgo);
+ if (pubKeyAlgo.equalsIgnoreCase("DSA")) {
+ sigAlgo = SSOConstants.DSA_SHA1;
+ jceSigAlgo = "SHA1withDSA";
+ }
+ LOG.fine("Using Signature algorithm " + sigAlgo);
+ ub.queryParam(SSOConstants.SIG_ALG, URLEncoder.encode(sigAlgo, "UTF-8"));
+
+ // Get the password
+ WSPasswordCallback[] cb = {new WSPasswordCallback(signatureUser, WSPasswordCallback.SIGNATURE)};
+ callbackHandler.handle(cb);
+ String password = cb[0].getPassword();
+
+ // Get the private key
+ PrivateKey privateKey = null;
+ try {
+ privateKey = crypto.getPrivateKey(signatureUser, password);
+ } catch (Exception ex) {
+ throw new WSSecurityException(ex.getMessage(), ex);
+ }
+
+ // Sign the request
+ Signature signature = Signature.getInstance(jceSigAlgo);
+ signature.initSign(privateKey);
+ signature.update(ub.toString().getBytes("UTF-8"));
+ byte[] signBytes = signature.sign();
+
+ String encodedSignature = Base64.encode(signBytes);
+
+ ub.queryParam(SSOConstants.SIGNATURE, URLEncoder.encode(encodedSignature, "UTF-8"));
+
+ }
}