Add the ability to sign SAML SSO requests
Project: http://git-wip-us.apache.org/repos/asf/cxf-fediz/repo Commit: http://git-wip-us.apache.org/repos/asf/cxf-fediz/commit/03d9a99c Tree: http://git-wip-us.apache.org/repos/asf/cxf-fediz/tree/03d9a99c Diff: http://git-wip-us.apache.org/repos/asf/cxf-fediz/diff/03d9a99c Branch: refs/heads/master Commit: 03d9a99c93dccf8d4faf17722ef26d0e7d858f30 Parents: fd36610 Author: Colm O hEigeartaigh <[email protected]> Authored: Mon Mar 16 16:24:16 2015 +0000 Committer: Colm O hEigeartaigh <[email protected]> Committed: Mon Mar 16 16:24:16 2015 +0000 ---------------------------------------------------------------------- .../TrustedIdpSAMLProtocolHandler.java | 102 +++++++++++++++---- .../idp/service/jpa/TrustedIdpDAOJPAImpl.java | 5 +- 2 files changed, 85 insertions(+), 22 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/03d9a99c/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/protocols/TrustedIdpSAMLProtocolHandler.java ---------------------------------------------------------------------- diff --git a/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/protocols/TrustedIdpSAMLProtocolHandler.java b/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/protocols/TrustedIdpSAMLProtocolHandler.java index e1b8879..18465f8 100644 --- a/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/protocols/TrustedIdpSAMLProtocolHandler.java +++ b/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/protocols/TrustedIdpSAMLProtocolHandler.java @@ -27,6 +27,9 @@ import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLEncoder; +import java.security.PrivateKey; +import java.security.Signature; +import java.security.cert.X509Certificate; import java.util.zip.DataFormatException; import javax.servlet.http.HttpServletRequest; @@ -39,6 +42,7 @@ import org.apache.cxf.common.util.Base64Exception; import org.apache.cxf.common.util.Base64Utility; import org.apache.cxf.common.util.StringUtils; import org.apache.cxf.fediz.core.FederationConstants; +import org.apache.cxf.fediz.core.util.CertsUtils; import org.apache.cxf.fediz.service.idp.domain.Idp; import org.apache.cxf.fediz.service.idp.domain.TrustedIdp; import org.apache.cxf.fediz.service.idp.spi.TrustedIdpProtocolHandler; @@ -51,12 +55,14 @@ import org.apache.cxf.rs.security.saml.sso.DefaultAuthnRequestBuilder; import org.apache.cxf.rs.security.saml.sso.SSOConstants; import org.apache.cxf.staxutils.StaxUtils; import org.apache.cxf.ws.security.tokenstore.SecurityToken; +import org.apache.wss4j.common.crypto.Crypto; import org.apache.wss4j.common.ext.WSSecurityException; import org.apache.wss4j.common.saml.OpenSAMLUtil; import org.apache.wss4j.common.util.DOM2Writer; import org.apache.wss4j.common.util.XMLUtils; import org.apache.wss4j.dom.WSConstants; import org.apache.xml.security.stax.impl.util.IDGenerator; +import org.apache.xml.security.utils.Base64; import org.opensaml.saml2.core.AuthnRequest; import org.opensaml.xml.XMLObject; import org.slf4j.Logger; @@ -100,9 +106,9 @@ public class TrustedIdpSAMLProtocolHandler implements TrustedIdpProtocolHandler authnRequestBuilder.createAuthnRequest( null, idp.getRealm(), idp.getIdpUrl().toString() ); - // if (isSignRequest()) { - // authnRequest.setDestination(idpServiceAddress); - //} + if (trustedIdp.isSignRequest()) { + authnRequest.setDestination(trustedIdp.getUrl()); + } Element authnRequestElement = OpenSAMLUtil.toDom(authnRequest, doc); String authnRequestEncoded = encodeAuthnRequest(authnRequestElement); @@ -116,15 +122,13 @@ public class TrustedIdpSAMLProtocolHandler implements TrustedIdpProtocolHandler if (wctx != null) { ub.queryParam(SSOConstants.RELAY_STATE, wctx); } - //if (isSignRequest()) { - // signRequest(urlEncodedRequest, info.getRelayState(), ub); - //} - - /*context.abortWith(Response.seeOther(ub.build()) - .header(HttpHeaders.CACHE_CONTROL, "no-cache, no-store") - .header("Pragma", "no-cache") - .build());*/ + if (trustedIdp.isSignRequest()) { + signRequest(urlEncodedRequest, wctx, idp, ub); + } + // TODO How to set headers here? + // .header(HttpHeaders.CACHE_CONTROL, "no-cache, no-store") + // .header("Pragma", "no-cache") return ub.build().toURL(); } catch (MalformedURLException ex) { LOG.error("Invalid Redirect URL for Trusted Idp", ex); @@ -139,15 +143,6 @@ public class TrustedIdpSAMLProtocolHandler implements TrustedIdpProtocolHandler } - protected String encodeAuthnRequest(Element authnRequest) throws IOException { - String requestMessage = DOM2Writer.nodeToString(authnRequest); - - DeflateEncoderDecoder encoder = new DeflateEncoderDecoder(); - byte[] deflatedBytes = encoder.deflateToken(requestMessage.getBytes("UTF-8")); - - return Base64Utility.encode(deflatedBytes); - } - @Override public SecurityToken mapSignInResponse(RequestContext context, Idp idp, TrustedIdp trustedIdp) { @@ -199,6 +194,73 @@ public class TrustedIdpSAMLProtocolHandler implements TrustedIdpProtocolHandler throw new IllegalStateException("Unexpected exception occured: " + ex.getMessage()); } } + + private String encodeAuthnRequest(Element authnRequest) throws IOException { + String requestMessage = DOM2Writer.nodeToString(authnRequest); + + DeflateEncoderDecoder encoder = new DeflateEncoderDecoder(); + byte[] deflatedBytes = encoder.deflateToken(requestMessage.getBytes("UTF-8")); + + return Base64Utility.encode(deflatedBytes); + } + + /** + * Sign a request according to the redirect binding spec for Web SSO + */ + private void signRequest( + String authnRequest, + String relayState, + Idp config, + UriBuilder ub + ) throws Exception { + Crypto crypto = CertsUtils.createCrypto(config.getCertificate()); + if (crypto == null) { + LOG.error("No crypto instance of properties file configured for signature"); + throw new IllegalStateException("Invalid IdP configuration"); + } + + String alias = crypto.getDefaultX509Identifier(); + X509Certificate cert = CertsUtils.getX509Certificate(crypto, alias); + if (cert == null) { + LOG.error("No cert was found to sign the request using alias: " + alias); + throw new IllegalStateException("Invalid IdP configuration"); + } + + String sigAlgo = SSOConstants.RSA_SHA1; + String pubKeyAlgo = cert.getPublicKey().getAlgorithm(); + String jceSigAlgo = "SHA1withRSA"; + LOG.debug("automatic sig algo detection: " + pubKeyAlgo); + if (pubKeyAlgo.equalsIgnoreCase("DSA")) { + sigAlgo = SSOConstants.DSA_SHA1; + jceSigAlgo = "SHA1withDSA"; + } + LOG.debug("Using Signature algorithm " + sigAlgo); + + ub.queryParam(SSOConstants.SIG_ALG, URLEncoder.encode(sigAlgo, "UTF-8")); + + // Get the password + String password = config.getCertificatePassword(); + + // Get the private key + PrivateKey privateKey = crypto.getPrivateKey(alias, password); + + // Sign the request + Signature signature = Signature.getInstance(jceSigAlgo); + signature.initSign(privateKey); + + String requestToSign = + SSOConstants.SAML_REQUEST + "=" + authnRequest + "&" + + SSOConstants.RELAY_STATE + "=" + relayState + "&" + + SSOConstants.SIG_ALG + "=" + URLEncoder.encode(sigAlgo, "UTF-8"); + + signature.update(requestToSign.getBytes("UTF-8")); + byte[] signBytes = signature.sign(); + + String encodedSignature = Base64.encode(signBytes); + + ub.queryParam(SSOConstants.SIGNATURE, URLEncoder.encode(encodedSignature, "UTF-8")); + } + private Element readSAMLResponse( boolean postBinding, String samlResponse http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/03d9a99c/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/service/jpa/TrustedIdpDAOJPAImpl.java ---------------------------------------------------------------------- diff --git a/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/service/jpa/TrustedIdpDAOJPAImpl.java b/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/service/jpa/TrustedIdpDAOJPAImpl.java index 8d0f208..a7b5472 100644 --- a/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/service/jpa/TrustedIdpDAOJPAImpl.java +++ b/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/service/jpa/TrustedIdpDAOJPAImpl.java @@ -54,8 +54,7 @@ public class TrustedIdpDAOJPAImpl implements TrustedIdpDAO { Query query = null; query = em.createQuery("select t from TrustedIDP t"); - //@SuppressWarnings("rawtypes") - List idpEntities = query + List<?> idpEntities = query .setFirstResult(start) .setMaxResults(size) .getResultList(); @@ -130,6 +129,7 @@ public class TrustedIdpDAOJPAImpl implements TrustedIdpDAO { entity.setRealm(trustedIDP.getRealm()); entity.setTrustType(trustedIDP.getTrustType()); entity.setUrl(trustedIDP.getUrl()); + entity.setSignRequest(trustedIDP.isSignRequest()); } public static TrustedIdp entity2domain(TrustedIdpEntity entity) { @@ -145,6 +145,7 @@ public class TrustedIdpDAOJPAImpl implements TrustedIdpDAO { trustedIDP.setRealm(entity.getRealm()); trustedIDP.setTrustType(entity.getTrustType()); trustedIDP.setUrl(entity.getUrl()); + trustedIDP.setSignRequest(entity.isSignRequest()); return trustedIDP; }
