SAML UPDATE

支持腾讯云和阿里云SAML 单点登录,支持属性扩展
This commit is contained in:
shimingxy
2020-02-28 21:46:15 +08:00
parent 025912d143
commit 6d10df3098
20 changed files with 144 additions and 46 deletions

View File

@@ -86,11 +86,11 @@ public class MetadataEndpoint {
IDPSSODescriptor descriptor = metadataGenerator.buildIDPSSODescriptor();
descriptor.getSingleSignOnServices().add(metadataGenerator.getSingleSignOnService(WebContext.getHttpContextPath()+"/saml/v20/authorize/"+appId,null));
descriptor.getSingleSignOnServices().add(metadataGenerator.getSingleSignOnService(WebContext.getHttpContextPath()+"/saml/v20/authz/"+appId,null));
descriptor.getSingleSignOnServices().add(metadataGenerator.getSingleSignOnService(WebContext.getHttpContextPath()+"/saml/v20/authorize/"+appId,SAMLConstants.SAML2_REDIRECT_BINDING_URI));
descriptor.getSingleSignOnServices().add(metadataGenerator.getSingleSignOnService(WebContext.getHttpContextPath()+"/saml/v20/authz/"+appId,SAMLConstants.SAML2_REDIRECT_BINDING_URI));
descriptor.getSingleSignOnServices().add(metadataGenerator.getSingleSignOnService(WebContext.getHttpContextPath()+"/saml/v20/authorize/"+appId,SAMLConstants.SAML2_POST_SIMPLE_SIGN_BINDING_URI));
descriptor.getSingleSignOnServices().add(metadataGenerator.getSingleSignOnService(WebContext.getHttpContextPath()+"/saml/v20/authz/"+appId,SAMLConstants.SAML2_POST_SIMPLE_SIGN_BINDING_URI));
descriptor.getSingleLogoutServices().add(metadataGenerator.getSingleLogoutService(WebContext.getHttpContextPath()+"/logout",null));

View File

@@ -7,6 +7,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.joda.time.DateTime;
import org.maxkey.authn.BasicAuthentication;
import org.maxkey.authz.saml.common.AuthnRequestInfo;
import org.maxkey.authz.saml.common.EndpointGenerator;
import org.maxkey.authz.saml20.binding.BindingAdapter;
@@ -48,7 +49,7 @@ public class AssertionEndpoint {
bindingAdapter = (BindingAdapter) request.getSession().getAttribute("samlv20Adapter");
logger.debug("saml20 assertion get session samlv20Adapter "+bindingAdapter);
AppsSAML20Details saml20Details = bindingAdapter.getSaml20Details();
logger.debug("saml20Details "+saml20Details.getExtendAttr());
AuthnRequestInfo authnRequestInfo = bindingAdapter.getAuthnRequestInfo();
if (authnRequestInfo == null) {
@@ -67,7 +68,10 @@ public class AssertionEndpoint {
grantedAuthority.add(anthGrantedAuthority);
}
//TODO:
String userName =authToken.getPrincipal().toString();
//String userName ="shimingxy@qq.com";
String userName =((BasicAuthentication )authToken.getPrincipal()).getJ_username();
//aly
//String userName ="admin@1729982683323703.onaliyun.com";
DateTime authnInstant = new DateTime(request.getSession().getCreationTime());
String remoteAddress=WebContext.getRequestIpAddress(request);

View File

@@ -75,7 +75,6 @@ public class AssertionGenerator {
AttributeStatement attributeStatement =attributeStatementGenerator.generateAttributeStatement(authorities, attributeMap);
assertion.getAttributeStatements().add(attributeStatement);
assertion.setID(idService.generateID());
assertion.setIssueInstant(timeService.getCurrentDateTime());

View File

@@ -5,6 +5,12 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import org.maxkey.authz.saml20.binding.BindingAdapter;
import org.maxkey.domain.ExtraAttr;
import org.maxkey.domain.ExtraAttrs;
import org.maxkey.domain.apps.AppsSAML20Details;
import org.maxkey.web.WebContext;
import org.opensaml.Configuration;
import org.opensaml.saml2.core.Attribute;
import org.opensaml.saml2.core.AttributeStatement;
@@ -14,10 +20,13 @@ import org.opensaml.saml2.core.impl.AttributeStatementBuilder;
import org.opensaml.xml.XMLObjectBuilderFactory;
import org.opensaml.xml.schema.XSString;
import org.opensaml.xml.schema.impl.XSStringBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.GrantedAuthority;
public class AttributeStatementGenerator {
private final static Logger logger = LoggerFactory.getLogger(AttributeStatementGenerator.class);
private final XMLObjectBuilderFactory builderFactory = Configuration.getBuilderFactory();
public AttributeStatement generateAttributeStatement(Collection<GrantedAuthority> authorities) {
@@ -44,22 +53,38 @@ public class AttributeStatementGenerator {
String key = entry.getKey();
String value = entry.getValue();
Attribute attribute=builderAttribute(key,value);
Attribute attribute=builderAttribute(key,value,Attribute.BASIC);
attributeStatement.getAttributes().add(attribute);
}
}
BindingAdapter bindingAdapter = (BindingAdapter) WebContext.getSession().getAttribute("samlv20Adapter");
AppsSAML20Details saml20Details = bindingAdapter.getSaml20Details();
logger.debug("ExtendAttr "+saml20Details.getExtendAttr());
ExtraAttrs extraAttrs=new ExtraAttrs(saml20Details.getExtendAttr());
for(ExtraAttr extraAttr : extraAttrs.getExtraAttrs()) {
logger.debug("Attribute : "+extraAttr.getAttr()+" , Vale : "+extraAttr.getValue()+" , Type : "+extraAttr.getType());
attributeStatement.getAttributes().add(builderAttribute(extraAttr.getAttr(),extraAttr.getValue(),extraAttr.getType()));
}
//tencent
//attributeStatement.getAttributes().add(builderAttribute("https://cloud.tencent.com/SAML/Attributes/Role","qcs::cam::uin/100013138092:roleName/cloud.tencent_maxkey,qcs::cam::uin/100013138092:saml-provider/maxkey",Attribute.UNSPECIFIED));
//attributeStatement.getAttributes().add(builderAttribute("https://cloud.tencent.com/SAML/Attributes/RoleSessionName","maxkey",Attribute.UNSPECIFIED));
//aliyun
//attributeStatement.getAttributes().add(builderAttribute("https://www.aliyun.com/SAML-Role/Attributes/RoleSessionName","2037230828547234327",Attribute.UNSPECIFIED));
//attributeStatement.getAttributes().add(builderAttribute("https://www.aliyun.com/SAML-Role/Attributes/Role","acs:ram::1729982683323703:role/maxkey,acs:ram::1729982683323703:saml-provider/maxkey",Attribute.UNSPECIFIED));
//attributeStatement.getAttributes().add(builderAttribute("https://www.aliyun.com/SAML-Role/Attributes/SessionDuration","1800",Attribute.UNSPECIFIED));
return attributeStatement;
}
public Attribute builderAttribute(String attributeName,String value ){
public Attribute builderAttribute(String attributeName,String value ,String nameFormat){
AttributeBuilder attributeBuilder = (AttributeBuilder) builderFactory.getBuilder(Attribute.DEFAULT_ELEMENT_NAME);
Attribute attribute = attributeBuilder.buildObject();
attribute.setName(attributeName);
// urn:oasis:names:tc:SAML:2.0:attrname-format:basic
attribute.setNameFormat(Attribute.DEFAULT_ELEMENT_LOCAL_NAME);
attribute.setNameFormat(nameFormat);
// Response/Assertion/AttributeStatement/Attribute/AttributeValue
XSStringBuilder stringBuilder = (XSStringBuilder) builderFactory.getBuilder(XSString.TYPE_NAME);
@@ -75,7 +100,7 @@ public class AttributeStatementGenerator {
// Response/Assertion/AttributeStatement/Attribute
AttributeBuilder attributeBuilder = (AttributeBuilder) builderFactory.getBuilder(Attribute.DEFAULT_ELEMENT_NAME);
Attribute attribute = attributeBuilder.buildObject();
attribute.setName(GrantedAuthority.class.getName());
attribute.setName("GrantedAuthority");
// urn:oasis:names:tc:SAML:2.0:attrname-format:basic
attribute.setNameFormat(Attribute.BASIC);

View File

@@ -26,8 +26,18 @@ import org.opensaml.xml.encryption.EncryptionConstants;
import org.opensaml.xml.encryption.EncryptionException;
import org.opensaml.xml.encryption.EncryptionParameters;
import org.opensaml.xml.encryption.KeyEncryptionParameters;
import org.opensaml.xml.io.Marshaller;
import org.opensaml.xml.io.MarshallerFactory;
import org.opensaml.xml.io.MarshallingException;
import org.opensaml.xml.security.BasicSecurityConfiguration;
import org.opensaml.xml.security.credential.BasicCredential;
import org.opensaml.xml.security.credential.Credential;
import org.opensaml.xml.security.keyinfo.KeyInfoGeneratorFactory;
import org.opensaml.xml.signature.Signature;
import org.opensaml.xml.signature.SignatureConstants;
import org.opensaml.xml.signature.SignatureException;
import org.opensaml.xml.signature.Signer;
import org.opensaml.xml.signature.impl.SignatureBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.GrantedAuthority;
@@ -87,6 +97,10 @@ public class AuthnResponseGenerator {
authnInstant);
try{
logger.debug("authResponse.isSigned "+authResponse.isSigned());
//assertion.setSignature(newSignature);
if(BOOLEAN.isTrue(saml20Details.getEncrypted())) {
// Assume this contains a recipient's RSA public
logger.info("begin to encrypt assertion");
@@ -107,20 +121,48 @@ public class AuthnResponseGenerator {
encrypter.setKeyPlacement(KeyPlacement.PEER);
EncryptedAssertion encryptedAssertion = encrypter.encrypt(assertion);
authResponse.getEncryptedAssertions().add(encryptedAssertion);
} else {
authResponse.getAssertions().add(assertion);
}
}
SignatureBuilder signatureBuilder = (SignatureBuilder) builderFactory.getBuilder(Signature.DEFAULT_ELEMENT_NAME);
BasicCredential basicCredential = new BasicCredential();
basicCredential.setPrivateKey(signingCredential.getPrivateKey());
Signature signature = signatureBuilder.buildObject();
signature.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
signature.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256);
signature.setSigningCredential(basicCredential);
KeyInfoGeneratorFactory keyInfoGeneratorFactory = Configuration
.getGlobalSecurityConfiguration()
.getKeyInfoGeneratorManager().getDefaultManager()
.getFactory(signingCredential);
signature.setKeyInfo(keyInfoGeneratorFactory.newInstance().generate(signingCredential));
BasicSecurityConfiguration config = (BasicSecurityConfiguration) Configuration.getGlobalSecurityConfiguration();
config.registerSignatureAlgorithmURI("RSA", SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256);
config.setSignatureReferenceDigestMethod(SignatureConstants.ALGO_ID_DIGEST_SHA256);
assertion.setSignature(signature);
Configuration.getMarshallerFactory().getMarshaller(assertion).marshall(assertion);
Signer.signObject(signature);
logger.debug("assertion.isSigned "+assertion.isSigned());;
authResponse.getAssertions().add(assertion);
}
catch (EncryptionException e) {
logger.info("Unable to encrypt assertion .");
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
authResponse.setIssuer(responseIssuer);
authResponse.setID(idService.generateID());
authResponse.setIssueInstant(timeService.getCurrentDateTime());
authResponse.setInResponseTo(inResponseTo);
authResponse.getAssertions().add(assertion);
//authResponse.getAssertions().add(assertion);
authResponse.setDestination(assertionConsumerURL);
authResponse.setStatus(statusGenerator.generateStatus(StatusCode.SUCCESS_URI));
return authResponse;

View File

@@ -3,7 +3,6 @@ package org.maxkey.authz.saml20.provider.xml;
import org.maxkey.authz.saml.service.TimeService;
import org.opensaml.Configuration;
import org.opensaml.saml2.core.NameID;
import org.opensaml.saml2.core.NameIDType;
import org.opensaml.saml2.core.Subject;
@@ -13,11 +12,10 @@ import org.opensaml.saml2.core.impl.NameIDBuilder;
import org.opensaml.saml2.core.impl.SubjectBuilder;
import org.opensaml.saml2.core.impl.SubjectConfirmationBuilder;
import org.opensaml.saml2.core.impl.SubjectConfirmationDataBuilder;
import org.opensaml.xml.XMLObjectBuilderFactory;
public class SubjectGenerator {
private final XMLObjectBuilderFactory builderFactory = Configuration.getBuilderFactory();
//private final XMLObjectBuilderFactory builderFactory = Configuration.getBuilderFactory();
private final TimeService timeService;
public SubjectGenerator(TimeService timeService) {
@@ -47,31 +45,30 @@ public class SubjectGenerator {
}
public NameID builderNameID(String value,String strSPNameQualifier){
//Response/Assertion/Subject/NameID
NameIDBuilder nameIDBuilder = (NameIDBuilder) builderFactory.getBuilder(NameID.DEFAULT_ELEMENT_NAME);
NameID nameID = nameIDBuilder.buildObject();
//Response/Assertion/Subject/NameID
NameID nameID = new NameIDBuilder().buildObject();
nameID.setValue(value);
nameID.setFormat(NameIDType.PERSISTENT);
nameID.setSPNameQualifier(strSPNameQualifier);
//nameID.setFormat(NameIDType.PERSISTENT);
nameID.setFormat(NameIDType.UNSPECIFIED);
//nameID.setSPNameQualifier(strSPNameQualifier);
return nameID;
}
public Subject builderSubject (NameID nameID){
//Response/Assertion/Subject
SubjectBuilder subjectBuilder = (SubjectBuilder)builderFactory.getBuilder(Subject.DEFAULT_ELEMENT_NAME);
Subject subject = subjectBuilder.buildObject();
Subject subject = new SubjectBuilder().buildObject();
subject.setNameID(nameID);
return subject;
}
public SubjectConfirmation builderSubjectConfirmation(String recipient,String inResponseTo,int validInSeconds,String clientAddress){
SubjectConfirmationBuilder subjectConfirmationBuilder = (SubjectConfirmationBuilder)builderFactory.getBuilder(SubjectConfirmation.DEFAULT_ELEMENT_NAME);
SubjectConfirmation subjectConfirmation = subjectConfirmationBuilder.buildObject();
//SubjectConfirmationBuilder subjectConfirmationBuilder = (SubjectConfirmationBuilder)builderFactory.getBuilder(SubjectConfirmation.DEFAULT_ELEMENT_NAME);
SubjectConfirmation subjectConfirmation = new SubjectConfirmationBuilder().buildObject();
subjectConfirmation.setMethod(SubjectConfirmation.METHOD_BEARER);
SubjectConfirmationDataBuilder subjectConfirmationDataBuilder = (SubjectConfirmationDataBuilder)builderFactory.getBuilder(SubjectConfirmationData.DEFAULT_ELEMENT_NAME);
SubjectConfirmationData subjectConfirmationData = subjectConfirmationDataBuilder.buildObject();
//SubjectConfirmationDataBuilder subjectConfirmationDataBuilder = (SubjectConfirmationDataBuilder)builderFactory.getBuilder(SubjectConfirmationData.DEFAULT_ELEMENT_NAME);
SubjectConfirmationData subjectConfirmationData = new SubjectConfirmationDataBuilder().buildObject();
subjectConfirmationData.setRecipient(recipient);
//if idp-init not need inResponseTo