sign artifact resolve-code + post binding
This commit is contained in:
parent
6c36253f09
commit
ff6d068ddd
|
@ -0,0 +1,52 @@
|
||||||
|
package eu.eudat.controllers;
|
||||||
|
|
||||||
|
import eu.eudat.logic.security.CustomAuthenticationProvider;
|
||||||
|
import eu.eudat.logic.security.validators.TokenValidatorFactoryImpl;
|
||||||
|
import eu.eudat.logic.services.ApiContext;
|
||||||
|
import eu.eudat.models.data.login.LoginInfo;
|
||||||
|
import eu.eudat.models.data.principal.PrincipalModel;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@CrossOrigin
|
||||||
|
@RequestMapping(value = {"/api/auth/saml2"})
|
||||||
|
public class Saml2PostBinding extends BaseController {
|
||||||
|
|
||||||
|
private CustomAuthenticationProvider customAuthenticationProvider;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public Saml2PostBinding(ApiContext apiContext, CustomAuthenticationProvider customAuthenticationProvider) {
|
||||||
|
super(apiContext);
|
||||||
|
this.customAuthenticationProvider = customAuthenticationProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(method = RequestMethod.POST, value = {"/postBinding"}, consumes = "application/x-www-form-urlencoded")
|
||||||
|
public @ResponseBody
|
||||||
|
ResponseEntity<Void> verify(@RequestParam(value = "SAMLResponse") String SAMLResponse, @RequestParam(value = "RelayState") String RelayState) throws GeneralSecurityException {
|
||||||
|
|
||||||
|
Map<String, String> map = Arrays.stream(RelayState.split("&")).map(s -> s.split("=")).collect(Collectors.toMap(e -> e[0], e -> e[1]));
|
||||||
|
|
||||||
|
LoginInfo loginInfo = new LoginInfo();
|
||||||
|
loginInfo.setTicket(SAMLResponse);
|
||||||
|
loginInfo.setProvider(TokenValidatorFactoryImpl.LoginProvider.CONFIGURABLE.getValue());
|
||||||
|
Map<String, String> providerId = new HashMap<>();
|
||||||
|
providerId.put("configurableLoginId", map.get("configurableLoginId"));
|
||||||
|
loginInfo.setData(providerId);
|
||||||
|
|
||||||
|
PrincipalModel principal = this.customAuthenticationProvider.authenticate(loginInfo);
|
||||||
|
|
||||||
|
return ResponseEntity.status(HttpStatus.FOUND).header(HttpHeaders.LOCATION, "http://localhost:4200/login/external/saml?token=" + principal.getToken().toString()).build();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -80,11 +80,16 @@ public class Saml2ConfigurableProvider extends ConfigurableProvider {
|
||||||
private String keyPassword;
|
private String keyPassword;
|
||||||
private boolean responseSigned;
|
private boolean responseSigned;
|
||||||
private boolean assertionSigned;
|
private boolean assertionSigned;
|
||||||
|
private boolean signatureRequired;
|
||||||
|
private String signatureKeyAlias;
|
||||||
|
private String signaturePath;
|
||||||
|
private String signatureKeyStorePassword;
|
||||||
|
private String signatureKeyPassword;
|
||||||
private SAML2UsingFormat usingFormat;
|
private SAML2UsingFormat usingFormat;
|
||||||
private Map<String, SAML2AttributeType> attributeTypes;
|
private Map<String, SAML2AttributeType> attributeTypes;
|
||||||
private Map<String, String> configurableUserFromAttributes;
|
private Map<String, String> configurableUserFromAttributes;
|
||||||
private String binding;
|
private String binding;
|
||||||
//private String assertionConsumerServiceUrl;
|
private String assertionConsumerServiceUrl;
|
||||||
|
|
||||||
public String getSpEntityId() {
|
public String getSpEntityId() {
|
||||||
return spEntityId;
|
return spEntityId;
|
||||||
|
@ -177,6 +182,41 @@ public class Saml2ConfigurableProvider extends ConfigurableProvider {
|
||||||
this.assertionSigned = assertionSigned;
|
this.assertionSigned = assertionSigned;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isSignatureRequired() {
|
||||||
|
return signatureRequired;
|
||||||
|
}
|
||||||
|
public void setSignatureRequired(boolean signatureRequired) {
|
||||||
|
this.signatureRequired = signatureRequired;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSignatureKeyAlias() {
|
||||||
|
return signatureKeyAlias;
|
||||||
|
}
|
||||||
|
public void setSignatureKeyAlias(String signatureKeyAlias) {
|
||||||
|
this.signatureKeyAlias = signatureKeyAlias;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSignaturePath() {
|
||||||
|
return signaturePath;
|
||||||
|
}
|
||||||
|
public void setSignaturePath(String signaturePath) {
|
||||||
|
this.signaturePath = signaturePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSignatureKeyStorePassword() {
|
||||||
|
return signatureKeyStorePassword;
|
||||||
|
}
|
||||||
|
public void setSignatureKeyStorePassword(String signatureKeyStorePassword) {
|
||||||
|
this.signatureKeyStorePassword = signatureKeyStorePassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSignatureKeyPassword() {
|
||||||
|
return signatureKeyPassword;
|
||||||
|
}
|
||||||
|
public void setSignatureKeyPassword(String signatureKeyPassword) {
|
||||||
|
this.signatureKeyPassword = signatureKeyPassword;
|
||||||
|
}
|
||||||
|
|
||||||
public SAML2UsingFormat getUsingFormat() {
|
public SAML2UsingFormat getUsingFormat() {
|
||||||
return usingFormat;
|
return usingFormat;
|
||||||
}
|
}
|
||||||
|
@ -205,11 +245,11 @@ public class Saml2ConfigurableProvider extends ConfigurableProvider {
|
||||||
this.binding = binding;
|
this.binding = binding;
|
||||||
}
|
}
|
||||||
|
|
||||||
// public String getAssertionConsumerServiceUrl() {
|
public String getAssertionConsumerServiceUrl() {
|
||||||
// return assertionConsumerServiceUrl;
|
return assertionConsumerServiceUrl;
|
||||||
// }
|
}
|
||||||
// public void setAssertionConsumerServiceUrl(String assertionConsumerServiceUrl) {
|
public void setAssertionConsumerServiceUrl(String assertionConsumerServiceUrl) {
|
||||||
// this.assertionConsumerServiceUrl = assertionConsumerServiceUrl;
|
this.assertionConsumerServiceUrl = assertionConsumerServiceUrl;
|
||||||
// }
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ public class Saml2ConfigurableProviderModel extends ConfigurableProviderModel {
|
||||||
private String spEntityId;
|
private String spEntityId;
|
||||||
private String idpUrl;
|
private String idpUrl;
|
||||||
private String binding;
|
private String binding;
|
||||||
//private String assertionConsumerServiceUrl;
|
private String assertionConsumerServiceUrl;
|
||||||
|
|
||||||
public String getSpEntityId() {
|
public String getSpEntityId() {
|
||||||
return spEntityId;
|
return spEntityId;
|
||||||
|
@ -32,12 +32,12 @@ public class Saml2ConfigurableProviderModel extends ConfigurableProviderModel {
|
||||||
this.binding = binding;
|
this.binding = binding;
|
||||||
}
|
}
|
||||||
|
|
||||||
// public String getAssertionConsumerServiceUrl() {
|
public String getAssertionConsumerServiceUrl() {
|
||||||
// return assertionConsumerServiceUrl;
|
return assertionConsumerServiceUrl;
|
||||||
// }
|
}
|
||||||
// public void setAssertionConsumerServiceUrl(String assertionConsumerServiceUrl) {
|
public void setAssertionConsumerServiceUrl(String assertionConsumerServiceUrl) {
|
||||||
// this.assertionConsumerServiceUrl = assertionConsumerServiceUrl;
|
this.assertionConsumerServiceUrl = assertionConsumerServiceUrl;
|
||||||
// }
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Saml2ConfigurableProviderModel fromDataModel(ConfigurableProvider entity) {
|
public Saml2ConfigurableProviderModel fromDataModel(ConfigurableProvider entity) {
|
||||||
|
@ -49,7 +49,7 @@ public class Saml2ConfigurableProviderModel extends ConfigurableProviderModel {
|
||||||
model.setSpEntityId(((Saml2ConfigurableProvider)entity).getSpEntityId());
|
model.setSpEntityId(((Saml2ConfigurableProvider)entity).getSpEntityId());
|
||||||
model.setIdpUrl(((Saml2ConfigurableProvider)entity).getIdpUrl());
|
model.setIdpUrl(((Saml2ConfigurableProvider)entity).getIdpUrl());
|
||||||
model.setBinding(((Saml2ConfigurableProvider)entity).getBinding());
|
model.setBinding(((Saml2ConfigurableProvider)entity).getBinding());
|
||||||
//model.setAssertionConsumerServiceUrl(((Saml2ConfigurableProvider)entity).getAssertionConsumerServiceUrl());
|
model.setAssertionConsumerServiceUrl(((Saml2ConfigurableProvider)entity).getAssertionConsumerServiceUrl());
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,7 @@ public class ConfigurableProviderTokenValidator implements TokenValidator {
|
||||||
Assertion saml2Assertion = null;
|
Assertion saml2Assertion = null;
|
||||||
try {
|
try {
|
||||||
Saml2ConfigurableProvider saml2Provider = (Saml2ConfigurableProvider)configurableProvider;
|
Saml2ConfigurableProvider saml2Provider = (Saml2ConfigurableProvider)configurableProvider;
|
||||||
if(saml2Provider.getBinding().equals("Redirect"))
|
if(saml2Provider.getBinding().equals("Redirect") || saml2Provider.getBinding().equals("Post"))
|
||||||
saml2Assertion = Saml2SSOUtils.processResponse(credentials.getTicket(), saml2Provider);
|
saml2Assertion = Saml2SSOUtils.processResponse(credentials.getTicket(), saml2Provider);
|
||||||
else if(saml2Provider.getBinding().equals("Artifact"))
|
else if(saml2Provider.getBinding().equals("Artifact"))
|
||||||
saml2Assertion = Saml2SSOUtils.processArtifactResponse(credentials.getTicket(), saml2Provider);
|
saml2Assertion = Saml2SSOUtils.processArtifactResponse(credentials.getTicket(), saml2Provider);
|
||||||
|
|
|
@ -20,17 +20,18 @@ import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
import org.apache.http.impl.client.HttpClientBuilder;
|
import org.apache.http.impl.client.HttpClientBuilder;
|
||||||
import org.apache.http.impl.client.HttpClients;
|
import org.apache.http.impl.client.HttpClients;
|
||||||
import org.apache.http.ssl.SSLContextBuilder;
|
import org.apache.http.ssl.SSLContextBuilder;
|
||||||
|
import org.apache.xml.security.c14n.Canonicalizer;
|
||||||
|
import org.apache.xml.security.signature.XMLSignature;
|
||||||
import org.opensaml.core.config.ConfigurationService;
|
import org.opensaml.core.config.ConfigurationService;
|
||||||
import org.opensaml.core.config.InitializationException;
|
import org.opensaml.core.config.InitializationException;
|
||||||
import org.opensaml.core.config.InitializationService;
|
import org.opensaml.core.config.InitializationService;
|
||||||
import org.opensaml.core.criterion.EntityIdCriterion;
|
import org.opensaml.core.criterion.EntityIdCriterion;
|
||||||
import org.opensaml.core.xml.XMLObject;
|
import org.opensaml.core.xml.XMLObject;
|
||||||
import org.opensaml.core.xml.XMLObjectBuilderFactory;
|
import org.opensaml.core.xml.XMLObjectBuilder;
|
||||||
import org.opensaml.core.xml.config.XMLObjectProviderRegistry;
|
import org.opensaml.core.xml.config.XMLObjectProviderRegistry;
|
||||||
import org.opensaml.core.xml.io.*;
|
import org.opensaml.core.xml.io.*;
|
||||||
import org.opensaml.core.xml.schema.*;
|
import org.opensaml.core.xml.schema.*;
|
||||||
import org.opensaml.saml.common.SAMLObject;
|
import org.opensaml.saml.common.SAMLObject;
|
||||||
import org.opensaml.saml.common.SAMLObjectBuilder;
|
|
||||||
import org.opensaml.saml.common.SAMLVersion;
|
import org.opensaml.saml.common.SAMLVersion;
|
||||||
import org.opensaml.saml.common.xml.SAMLConstants;
|
import org.opensaml.saml.common.xml.SAMLConstants;
|
||||||
import org.opensaml.saml.criterion.EntityRoleCriterion;
|
import org.opensaml.saml.criterion.EntityRoleCriterion;
|
||||||
|
@ -47,7 +48,7 @@ import org.opensaml.security.credential.UsageType;
|
||||||
import org.opensaml.security.criteria.UsageCriterion;
|
import org.opensaml.security.criteria.UsageCriterion;
|
||||||
import org.opensaml.security.x509.BasicX509Credential;
|
import org.opensaml.security.x509.BasicX509Credential;
|
||||||
import org.opensaml.security.x509.X509Credential;
|
import org.opensaml.security.x509.X509Credential;
|
||||||
import org.opensaml.soap.common.SOAPObjectBuilder;
|
import org.opensaml.security.x509.impl.KeyStoreX509CredentialAdapter;
|
||||||
import org.opensaml.soap.soap11.Body;
|
import org.opensaml.soap.soap11.Body;
|
||||||
import org.opensaml.soap.soap11.Envelope;
|
import org.opensaml.soap.soap11.Envelope;
|
||||||
import org.opensaml.xml.util.Base64;
|
import org.opensaml.xml.util.Base64;
|
||||||
|
@ -55,7 +56,11 @@ import org.opensaml.xmlsec.config.impl.DefaultSecurityConfigurationBootstrap;
|
||||||
import org.opensaml.xmlsec.encryption.EncryptedKey;
|
import org.opensaml.xmlsec.encryption.EncryptedKey;
|
||||||
import org.opensaml.xmlsec.keyinfo.KeyInfoCredentialResolver;
|
import org.opensaml.xmlsec.keyinfo.KeyInfoCredentialResolver;
|
||||||
import org.opensaml.xmlsec.keyinfo.impl.StaticKeyInfoCredentialResolver;
|
import org.opensaml.xmlsec.keyinfo.impl.StaticKeyInfoCredentialResolver;
|
||||||
|
import org.opensaml.xmlsec.signature.KeyInfo;
|
||||||
|
import org.opensaml.xmlsec.signature.Signature;
|
||||||
|
import org.opensaml.xmlsec.signature.X509Data;
|
||||||
import org.opensaml.xmlsec.signature.support.SignatureValidator;
|
import org.opensaml.xmlsec.signature.support.SignatureValidator;
|
||||||
|
import org.opensaml.xmlsec.signature.support.Signer;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
|
@ -67,6 +72,7 @@ import org.w3c.dom.ls.LSSerializer;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
import javax.crypto.SecretKey;
|
import javax.crypto.SecretKey;
|
||||||
|
import javax.xml.namespace.QName;
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
@ -78,6 +84,7 @@ import java.io.*;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.*;
|
import java.security.*;
|
||||||
|
import java.security.cert.CertificateEncodingException;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
@ -144,6 +151,17 @@ public class Saml2SSOUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static XMLObject buildXMLObject(QName objectQName) throws Exception {
|
||||||
|
|
||||||
|
doBootstrap();
|
||||||
|
XMLObjectBuilder builder = registry.getBuilderFactory().getBuilder(objectQName);
|
||||||
|
if (builder == null) {
|
||||||
|
throw new Exception("Unable to retrieve builder for object QName " + objectQName);
|
||||||
|
}
|
||||||
|
return builder.buildObject(objectQName.getNamespaceURI(), objectQName.getLocalPart(), objectQName.getPrefix());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public static String getAttributeName(Attribute attribute, Saml2ConfigurableProvider.SAML2UsingFormat usingFormat){
|
public static String getAttributeName(Attribute attribute, Saml2ConfigurableProvider.SAML2UsingFormat usingFormat){
|
||||||
String friendlyName = attribute.getFriendlyName();
|
String friendlyName = attribute.getFriendlyName();
|
||||||
String name = attribute.getName();
|
String name = attribute.getName();
|
||||||
|
@ -231,7 +249,7 @@ public class Saml2SSOUtils {
|
||||||
|
|
||||||
doBootstrap();
|
doBootstrap();
|
||||||
if (artifactString != null){
|
if (artifactString != null){
|
||||||
ArtifactResolve artifactResolve = generateArtifactResolveReq(artifactString, saml2Provider.getSpEntityId());
|
ArtifactResolve artifactResolve = generateArtifactResolveReq(artifactString, saml2Provider);
|
||||||
ArtifactResponse artifactResponse = sendArtifactResolveRequest(artifactResolve, saml2Provider.getIdpArtifactUrl());
|
ArtifactResponse artifactResponse = sendArtifactResolveRequest(artifactResolve, saml2Provider.getIdpArtifactUrl());
|
||||||
Response saml2Response = (Response)artifactResponse.getMessage();
|
Response saml2Response = (Response)artifactResponse.getMessage();
|
||||||
return processSSOResponse(saml2Response, saml2Provider);
|
return processSSOResponse(saml2Response, saml2Provider);
|
||||||
|
@ -242,34 +260,27 @@ public class Saml2SSOUtils {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ArtifactResolve generateArtifactResolveReq(String samlArtReceived, String spEntityId) {
|
private static ArtifactResolve generateArtifactResolveReq(String samlArtReceived, Saml2ConfigurableProvider saml2Provider) throws Exception {
|
||||||
|
|
||||||
ArtifactResolve artifactResolve = createArtifactResolveObject(samlArtReceived, spEntityId);
|
ArtifactResolve artifactResolve = createArtifactResolveObject(samlArtReceived, saml2Provider.getSpEntityId());
|
||||||
// if (config.isEnableArtifactResolveSigning()) {
|
if (saml2Provider.isSignatureRequired()) {
|
||||||
// artifactResolve = signArtifactResolveReq(artifactResolve);
|
signArtifactResolveReq(artifactResolve, saml2Provider);
|
||||||
// }
|
}
|
||||||
return artifactResolve;
|
return artifactResolve;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ArtifactResolve createArtifactResolveObject(String samlArtReceived, String spEntityId) {
|
private static ArtifactResolve createArtifactResolveObject(String samlArtReceived, String spEntityId) throws Exception {
|
||||||
|
|
||||||
XMLObjectBuilderFactory builderFactory = registry.getBuilderFactory();
|
ArtifactResolve artifactResolve = (ArtifactResolve)buildXMLObject(ArtifactResolve.DEFAULT_ELEMENT_NAME);
|
||||||
|
|
||||||
SAMLObjectBuilder<ArtifactResolve> artifactResolveBuilder =
|
|
||||||
(SAMLObjectBuilder<ArtifactResolve>) builderFactory.getBuilder(ArtifactResolve.DEFAULT_ELEMENT_NAME);
|
|
||||||
ArtifactResolve artifactResolve = artifactResolveBuilder.buildObject();
|
|
||||||
artifactResolve.setVersion(SAMLVersion.VERSION_20);
|
artifactResolve.setVersion(SAMLVersion.VERSION_20);
|
||||||
artifactResolve.setID(UUID.randomUUID().toString());
|
artifactResolve.setID(UUID.randomUUID().toString());
|
||||||
artifactResolve.setIssueInstant(Instant.now());
|
artifactResolve.setIssueInstant(Instant.now());
|
||||||
|
|
||||||
SAMLObjectBuilder<Artifact> artifactBuilder =
|
Artifact artifact = (Artifact)buildXMLObject(Artifact.DEFAULT_ELEMENT_NAME);
|
||||||
(SAMLObjectBuilder<Artifact>) builderFactory.getBuilder(Artifact.DEFAULT_ELEMENT_NAME);
|
|
||||||
Artifact artifact = artifactBuilder.buildObject();
|
|
||||||
artifact.setValue(samlArtReceived);
|
artifact.setValue(samlArtReceived);
|
||||||
|
|
||||||
SAMLObjectBuilder<Issuer> issuerBuilder = (SAMLObjectBuilder<Issuer>) builderFactory.getBuilder(Issuer.DEFAULT_ELEMENT_NAME);
|
Issuer issuer = (Issuer)buildXMLObject(Issuer.DEFAULT_ELEMENT_NAME);
|
||||||
Issuer issuer = issuerBuilder.buildObject();
|
|
||||||
issuer.setValue(spEntityId);
|
issuer.setValue(spEntityId);
|
||||||
|
|
||||||
artifactResolve.setIssuer(issuer);
|
artifactResolve.setIssuer(issuer);
|
||||||
|
@ -279,6 +290,57 @@ public class Saml2SSOUtils {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void signArtifactResolveReq(ArtifactResolve artifactResolve, Saml2ConfigurableProvider saml2Provider) throws Exception {
|
||||||
|
|
||||||
|
try {
|
||||||
|
KeyStore ks = KeyStore.getInstance("JKS");
|
||||||
|
String archivePassword = saml2Provider.getSignatureKeyStorePassword();
|
||||||
|
char[] pwdArray = (archivePassword != null) ? archivePassword.toCharArray() : "changeit".toCharArray();
|
||||||
|
ks.load(new FileInputStream(saml2Provider.getSignaturePath()), pwdArray);
|
||||||
|
X509Credential cred = new KeyStoreX509CredentialAdapter(ks, saml2Provider.getSignatureKeyAlias(), saml2Provider.getSignatureKeyPassword().toCharArray());
|
||||||
|
Signature signature = setSignatureRaw(XMLSignature.ALGO_ID_SIGNATURE_RSA, cred);
|
||||||
|
artifactResolve.setSignature(signature);
|
||||||
|
|
||||||
|
List<Signature> signatureList = new ArrayList<>();
|
||||||
|
signatureList.add(signature);
|
||||||
|
|
||||||
|
MarshallerFactory marshallerFactory = registry.getMarshallerFactory();
|
||||||
|
Marshaller marshaller = marshallerFactory.getMarshaller(artifactResolve);
|
||||||
|
|
||||||
|
marshaller.marshall(artifactResolve);
|
||||||
|
|
||||||
|
org.apache.xml.security.Init.init();
|
||||||
|
Signer.signObjects(signatureList);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new Exception("Error while signing the SAML Request message", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Signature setSignatureRaw(String signatureAlgorithm, X509Credential cred) throws Exception {
|
||||||
|
|
||||||
|
Signature signature = (Signature)buildXMLObject(Signature.DEFAULT_ELEMENT_NAME);
|
||||||
|
signature.setSigningCredential(cred);
|
||||||
|
signature.setSignatureAlgorithm(signatureAlgorithm);
|
||||||
|
signature.setCanonicalizationAlgorithm(Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
|
||||||
|
|
||||||
|
try {
|
||||||
|
KeyInfo keyInfo = (KeyInfo)buildXMLObject(KeyInfo.DEFAULT_ELEMENT_NAME);
|
||||||
|
X509Data data = (X509Data)buildXMLObject(X509Data.DEFAULT_ELEMENT_NAME);
|
||||||
|
org.opensaml.xmlsec.signature.X509Certificate cert =
|
||||||
|
(org.opensaml.xmlsec.signature.X509Certificate) buildXMLObject(
|
||||||
|
org.opensaml.xmlsec.signature.X509Certificate.DEFAULT_ELEMENT_NAME);
|
||||||
|
String value = org.apache.commons.codec.binary.Base64.encodeBase64String(cred.getEntityCertificate().getEncoded());
|
||||||
|
cert.setValue(value);
|
||||||
|
data.getX509Certificates().add(cert);
|
||||||
|
keyInfo.getX509Datas().add(data);
|
||||||
|
signature.setKeyInfo(keyInfo);
|
||||||
|
return signature;
|
||||||
|
|
||||||
|
} catch (CertificateEncodingException e) {
|
||||||
|
throw new Exception("Error getting certificate", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static ArtifactResponse sendArtifactResolveRequest(ArtifactResolve artifactResolve, String idpArtifactUrl) throws Exception {
|
private static ArtifactResponse sendArtifactResolveRequest(ArtifactResolve artifactResolve, String idpArtifactUrl) throws Exception {
|
||||||
|
|
||||||
Envelope envelope = buildSOAPMessage(artifactResolve);
|
Envelope envelope = buildSOAPMessage(artifactResolve);
|
||||||
|
@ -297,17 +359,10 @@ public class Saml2SSOUtils {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Envelope buildSOAPMessage(SAMLObject samlMessage) {
|
private static Envelope buildSOAPMessage(SAMLObject samlMessage) throws Exception {
|
||||||
|
|
||||||
XMLObjectBuilderFactory builderFactory = registry.getBuilderFactory();
|
Envelope envelope = (Envelope)buildXMLObject(Envelope.DEFAULT_ELEMENT_NAME);
|
||||||
|
Body body = (Body)buildXMLObject(Body.DEFAULT_ELEMENT_NAME);
|
||||||
SOAPObjectBuilder<Envelope> envBuilder = (SOAPObjectBuilder<Envelope>) builderFactory.getBuilder(
|
|
||||||
Envelope.DEFAULT_ELEMENT_NAME);
|
|
||||||
Envelope envelope = envBuilder.buildObject();
|
|
||||||
|
|
||||||
SOAPObjectBuilder<Body> bodyBuilder = (SOAPObjectBuilder<Body>) builderFactory.getBuilder(
|
|
||||||
Body.DEFAULT_ELEMENT_NAME);
|
|
||||||
Body body = bodyBuilder.buildObject();
|
|
||||||
body.getUnknownXMLObjects().add(samlMessage);
|
body.getUnknownXMLObjects().add(samlMessage);
|
||||||
envelope.setBody(body);
|
envelope.setBody(body);
|
||||||
return envelope;
|
return envelope;
|
||||||
|
@ -459,10 +514,16 @@ public class Saml2SSOUtils {
|
||||||
doBootstrap();
|
doBootstrap();
|
||||||
if (saml2SSOResponse != null) {
|
if (saml2SSOResponse != null) {
|
||||||
byte[] decodedResponse = Base64.decode(saml2SSOResponse);
|
byte[] decodedResponse = Base64.decode(saml2SSOResponse);
|
||||||
ByteArrayInputStream bytesIn = new ByteArrayInputStream(decodedResponse);
|
String response;
|
||||||
InflaterInputStream inflater = new InflaterInputStream(bytesIn, new Inflater(true));
|
if(!saml2Provider.getBinding().equals("Post")){
|
||||||
String response = new BufferedReader(new InputStreamReader(inflater, StandardCharsets.UTF_8))
|
ByteArrayInputStream bytesIn = new ByteArrayInputStream(decodedResponse);
|
||||||
.lines().collect(Collectors.joining("\n"));
|
InflaterInputStream inflater = new InflaterInputStream(bytesIn, new Inflater(true));
|
||||||
|
response = new BufferedReader(new InputStreamReader(inflater, StandardCharsets.UTF_8))
|
||||||
|
.lines().collect(Collectors.joining("\n"));
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
response = new String(decodedResponse);
|
||||||
|
}
|
||||||
Response saml2Response = (Response) Saml2SSOUtils.unmarshall(response);
|
Response saml2Response = (Response) Saml2SSOUtils.unmarshall(response);
|
||||||
return processSSOResponse(saml2Response, saml2Provider);
|
return processSSOResponse(saml2Response, saml2Provider);
|
||||||
|
|
||||||
|
|
|
@ -4,4 +4,5 @@ export class Saml2ConfigurableProvider extends ConfigurableProvider{
|
||||||
spEntityId: string;
|
spEntityId: string;
|
||||||
idpUrl: string;
|
idpUrl: string;
|
||||||
binding: string;
|
binding: string;
|
||||||
|
assertionConsumerServiceUrl: string;
|
||||||
}
|
}
|
|
@ -181,4 +181,23 @@ export class AuthService extends BaseService {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getUserFromToken(token: string): Observable<Principal> {
|
||||||
|
this.actionUrl = this.configurationService.server + 'auth/';
|
||||||
|
const url = this.actionUrl + 'me';
|
||||||
|
let headers = this.headers;
|
||||||
|
headers = headers.set('AuthToken', token);
|
||||||
|
return this.http.post(url, null, { headers: headers }).pipe(
|
||||||
|
map((res: any) => {
|
||||||
|
const princ = this.current(res.payload);
|
||||||
|
princ.expiresAt = new Date(princ.expiresAt);
|
||||||
|
return princ;
|
||||||
|
}),
|
||||||
|
catchError((error: any) => {
|
||||||
|
this.clear();
|
||||||
|
const princ = this.current();
|
||||||
|
this.router.navigate(['/login']);
|
||||||
|
return observableOf<Principal>(princ);
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,17 +24,18 @@ export class SamlLoginService {
|
||||||
return routeParams.has('spId') ? routeParams.get('spId') : '';
|
return routeParams.has('spId') ? routeParams.get('spId') : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
getSamlLoginUrl(spEntityID: string, idpUrl: string, binding: string, configurableLoginId: string) {
|
getSamlLoginUrl(spEntityID: string, idpUrl: string, binding: string, assertionConsumerServiceUrl: string, configurableLoginId: string) {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
let protocolBinding = '';
|
let protocolBinding = '';
|
||||||
switch (binding) {
|
switch (binding) {
|
||||||
case "Redirect": protocolBinding = 'ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" '; break;
|
case "Redirect": protocolBinding = 'ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" '; break;
|
||||||
case "Artifact": protocolBinding = 'ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" '; break;
|
case "Artifact": protocolBinding = 'ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" '; break;
|
||||||
case "Post": protocolBinding = 'ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Post" '; break;
|
case "Post": protocolBinding = 'ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" '; break;
|
||||||
}
|
}
|
||||||
const authenticationRequest = '<saml2p:AuthnRequest xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" ID="_' + Guid.create() + '" Version="2.0" ' +
|
const authenticationRequest = '<saml2p:AuthnRequest xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" ID="_' + Guid.create() + '" Version="2.0" ' +
|
||||||
'IssueInstant="' + now.toISOString() + '" ' +
|
'IssueInstant="' + now.toISOString() + '" ' +
|
||||||
protocolBinding +
|
protocolBinding +
|
||||||
|
'AssertionConsumerServiceUrl="' + assertionConsumerServiceUrl + '" ' +
|
||||||
'Destination="' + idpUrl + '">' +
|
'Destination="' + idpUrl + '">' +
|
||||||
'<saml2:Issuer>' + spEntityID + '</saml2:Issuer>' +
|
'<saml2:Issuer>' + spEntityID + '</saml2:Issuer>' +
|
||||||
'</saml2p:AuthnRequest>';
|
'</saml2p:AuthnRequest>';
|
||||||
|
|
|
@ -86,7 +86,7 @@ export class ConfigurableLoginComponent extends BaseComponent implements OnInit
|
||||||
}
|
}
|
||||||
else if(this.provider.type === ConfigurableProviderType.Saml2){
|
else if(this.provider.type === ConfigurableProviderType.Saml2){
|
||||||
let provider = this.provider as Saml2ConfigurableProvider;
|
let provider = this.provider as Saml2ConfigurableProvider;
|
||||||
window.location.href = this.samlLoginService.getSamlLoginUrl(provider.spEntityId, provider.idpUrl, provider.binding, provider.configurableLoginId);
|
window.location.href = this.samlLoginService.getSamlLoginUrl(provider.spEntityId, provider.idpUrl, provider.binding, provider.assertionConsumerServiceUrl, provider.configurableLoginId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,8 +36,13 @@ export class SamlResponseLoginComponent extends BaseComponent implements OnInit
|
||||||
} else if (routeParams.SAMLResponse) {
|
} else if (routeParams.SAMLResponse) {
|
||||||
samlResponse = routeParams.SAMLResponse;
|
samlResponse = routeParams.SAMLResponse;
|
||||||
}
|
}
|
||||||
|
else if(routeParams.token){
|
||||||
|
this.authService.getUserFromToken(routeParams.token).pipe(takeUntil(this._destroyed))
|
||||||
|
.subscribe((result) => this.onAuthenticateSuccess(), (error) => this.onAuthenticateError(error));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (samlResponse == null) return;
|
if (samlResponse == null) this.router.navigate(['/login']);
|
||||||
|
|
||||||
const spId = this.samlLoginService.resolveSpId(routeParams.RelayState);
|
const spId = this.samlLoginService.resolveSpId(routeParams.RelayState);
|
||||||
const configurableLoginId = this.samlLoginService.resolveConfigurableLoginId(routeParams.RelayState);
|
const configurableLoginId = this.samlLoginService.resolveConfigurableLoginId(routeParams.RelayState);
|
||||||
|
|
Loading…
Reference in New Issue