Skip to content

Instantly share code, notes, and snippets.

@ichengchao
Created January 9, 2025 06:36
SAML&OIDC IdP Demo
import java.util.HashMap;
import java.util.Map;
import org.springframework.util.Assert;
import com.aliyuncs.CommonRequest;
import com.aliyuncs.CommonResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.http.ProtocolType;
import com.aliyuncs.profile.DefaultProfile;
import com.nimbusds.jose.Algorithm;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.JWSObject;
import com.nimbusds.jose.JWSSigner;
import com.nimbusds.jose.Payload;
import com.nimbusds.jose.crypto.RSASSASigner;
import com.nimbusds.jose.jwk.KeyUse;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.gen.RSAKeyGenerator;
public class OIDC_IdP_Mock {
// 证书的json串,避免每次重启的时候都重新生成证书
private static final String RasKeyJsonString = "{\"p\":\"-ns8s9wqHlGQq7Cw*****w\"}";
public static void main(String[] args) throws Exception {
String idToken = buildIDToken("https://oidctest.chengchao.name", "chengchao", "aliyunoss001");
String stsResult = getSTSTokenWithOIDC(idToken);
System.out.println(stsResult);
}
public static RSAKey generateRSAKey() throws Exception {
RSAKey raskey = new RSAKeyGenerator(2048)
.keyID("demokey_001")
.keyUse(new KeyUse("sig"))
.algorithm(new Algorithm("RS256"))
.generate();
return raskey;
}
public static String commonInvoke(IAcsClient client, String domain, String version, String action,
Map<String, String> params) throws Exception {
Assert.notNull(client, "client can not be null!");
Assert.hasText(domain, "domain can not be blank!");
Assert.hasText(version, "version can not be blank!");
Assert.hasText(action, "action can not be blank!");
CommonRequest request = new CommonRequest();
request.setSysDomain(domain);
request.setSysVersion(version);
request.setSysAction(action);
if (params != null && !params.isEmpty()) {
for (Map.Entry<String, String> entry : params.entrySet()) {
request.putQueryParameter(entry.getKey(), entry.getValue());
}
}
request.setSysProtocol(ProtocolType.HTTPS);
CommonResponse response = client.getCommonResponse(request);
return response.getData();
}
public static String getSTSTokenWithOIDC(String idToken) throws Exception {
DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou");
IAcsClient client = new DefaultAcsClient(profile);
String action = "AssumeRoleWithOIDC";
Map<String, String> params = new HashMap<>();
params.put("OIDCProviderArn", "acs:ram::17642*****:oidc-provider/OIDCTest001");
params.put("RoleArn", "acs:ram::17642*****:role/role-oidc001");
params.put("OIDCToken", idToken);
params.put("RoleSessionName", "chengchao");
String result = commonInvoke(client, "sts.cn-hangzhou.aliyuncs.com", "2015-04-01", action, params);
return result;
}
public static String buildIDToken(String issuer, String subject, String audience) throws Exception {
RSAKey MyRasKey = RSAKey.parse(RasKeyJsonString);
String nonce = "";
int oneweekseconds = 7 * 24 * 3600;
int t = (int)(System.currentTimeMillis() / 1000);
Map<String, Object> payload = new HashMap<>();
payload.put("iss", issuer);
payload.put("aud", audience);
payload.put("exp", t + oneweekseconds);
payload.put("iat", t);
payload.put("sub", subject);
payload.put("nonce", nonce);
payload.put("jti", subject);
JWSSigner signer = new RSASSASigner(MyRasKey);
JWSObject jwsObject = new JWSObject(
new JWSHeader.Builder(JWSAlgorithm.RS256).keyID(MyRasKey.getKeyID()).build(),
new Payload(JsonUtils.toJsonString(payload)));
jwsObject.sign(signer);
String result = jwsObject.serialize();
return result;
}
}
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>name.chengchao</groupId>
<artifactId>demo-saml</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.70</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.70</version>
</dependency>
<dependency>
<groupId>org.opensaml</groupId>
<artifactId>opensaml-core</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.opensaml</groupId>
<artifactId>opensaml-saml-api</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.opensaml</groupId>
<artifactId>opensaml-saml-impl</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>ognl</groupId>
<artifactId>ognl</artifactId>
<version>3.1.12</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>4.7.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.10.0</version>
</dependency>
<dependency>
<groupId>org.opensaml</groupId>
<artifactId>opensaml-security-api</artifactId>
<version>4.0.1</version>
</dependency>
<!-- jwt lib -->
<dependency>
<groupId>com.nimbusds</groupId>
<artifactId>nimbus-jose-jwt</artifactId>
<version>9.10.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
</dependencies>
</project>
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.cert.X509Certificate;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.commons.io.FileUtils;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.opensaml.core.config.InitializationService;
import org.opensaml.saml.common.xml.SAMLConstants;
import org.opensaml.saml.saml2.core.Response;
import org.opensaml.saml.saml2.core.impl.ResponseMarshaller;
import org.opensaml.saml.saml2.metadata.EntityDescriptor;
import org.opensaml.saml.saml2.metadata.IDPSSODescriptor;
import org.opensaml.saml.saml2.metadata.KeyDescriptor;
import org.opensaml.saml.saml2.metadata.SingleSignOnService;
import org.opensaml.saml.saml2.metadata.impl.EntityDescriptorBuilder;
import org.opensaml.saml.saml2.metadata.impl.EntityDescriptorMarshaller;
import org.opensaml.saml.saml2.metadata.impl.IDPSSODescriptorBuilder;
import org.opensaml.saml.saml2.metadata.impl.KeyDescriptorBuilder;
import org.opensaml.saml.saml2.metadata.impl.SingleSignOnServiceBuilder;
import org.opensaml.security.credential.UsageType;
import org.opensaml.security.x509.BasicX509Credential;
import org.opensaml.xmlsec.signature.KeyInfo;
import org.opensaml.xmlsec.signature.X509Data;
import org.opensaml.xmlsec.signature.impl.KeyInfoBuilder;
import org.opensaml.xmlsec.signature.impl.X509CertificateBuilder;
import org.opensaml.xmlsec.signature.impl.X509DataBuilder;
import org.w3c.dom.Element;
public class SAML_IdP_Mock {
public static final String ALIYUN_ROLE_SSO_IDENTIFIER = "urn:alibaba:cloudcomputing";
public static final String ALIYUN_ROLE_SSO_REPLYURL = "https://signin.aliyun.com/saml-role/sso";
public static final String IDP_ENTITY_ID = "chengchaoIdP-Demo";
public static final String IDP_LOGIN_LOCATION = "https://test.com/samlLogin.do";
public static void main(String[] args) throws Exception {
InitializationService.initialize();
String publicKeyString = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AM******";
String privateKeyString = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASC*******";
KeyPair keyPair = paserKeypair(publicKeyString, privateKeyString);
X509Certificate certificate = generateCertificate(keyPair);
String idpMetaXMLString = generateIdpMetaXML(certificate);
//生成IdP Metadata.xml文件
FileUtils.write(new File("/Users/charles/Desktop/chengchaoIdPMetadata.xml"), idpMetaXMLString, StandardCharsets.UTF_8);
//生成SAML Response
Map<String, String> attributeMap = new HashMap<>();
attributeMap.put("https://www.aliyun.com/SAML-Role/Attributes/RoleSessionName", "chengchao");
attributeMap.put("https://www.aliyun.com/SAML-Role/Attributes/Role", "acs:ram::17642*****:role/rolefordemoidp,acs:ram::17642*****:saml-provider/DemoIdP");
BasicX509Credential basicX509Credential = new BasicX509Credential(certificate, keyPair.getPrivate());
String samlResponseStr = buildSamlResponse(basicX509Credential,attributeMap);
String base64EncodeSAMLResponse = java.util.Base64.getEncoder().encodeToString(samlResponseStr.getBytes());
System.out.println(base64EncodeSAMLResponse);
}
public static String buildSamlResponse(BasicX509Credential basicX509Credential,Map<String, String> attributeMap) throws Exception {
Response responseInitial = SamlUtils.createSAMLResponse(null, ALIYUN_ROLE_SSO_IDENTIFIER,
ALIYUN_ROLE_SSO_REPLYURL, "demoNameID", attributeMap, basicX509Credential);
ResponseMarshaller marshaller = new ResponseMarshaller();
Element element = marshaller.marshall(responseInitial);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.transform(new DOMSource(element), new StreamResult(baos));
String responseStr = new String(baos.toByteArray());
return responseStr;
}
public static X509Certificate generateCertificate(KeyPair keyPair) throws Exception {
Security.addProvider(new BouncyCastleProvider());
X500Name issuer = new X500Name("CN=Chengchao CA");
X500Name subject = new X500Name("CN=Chengchao SSO Demo");
BigInteger serialNumber = BigInteger.valueOf(System.currentTimeMillis());
Date notBefore = Date.from(Instant.now().minus(1, ChronoUnit.DAYS));
Date notAfter = Date.from(Instant.now().plus(365, ChronoUnit.DAYS));
JcaX509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(
issuer,
serialNumber,
notBefore,
notAfter,
subject,
keyPair.getPublic());
ContentSigner signer = new JcaContentSignerBuilder("SHA256WithRSAEncryption")
.setProvider("BC")
.build(keyPair.getPrivate());
X509CertificateHolder certHolder = certBuilder.build(signer);
return new JcaX509CertificateConverter()
.setProvider("BC")
.getCertificate(certHolder);
}
public static KeyPair paserKeypair(String publicKeyString, String privateKeyString) throws Exception {
byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyString);
byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyString);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(publicKeyBytes));
PrivateKey privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes));
return new KeyPair(publicKey, privateKey);
}
public static void generateKeyPair() throws Exception {
// 1. 创建 KeyPairGenerator 对象,指定 RSA 算法
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
// 2. 初始化 KeyPairGenerator,设置密钥长度(2048 位)
keyPairGen.initialize(2048);
// 3. 生成密钥对
KeyPair keyPair = keyPairGen.generateKeyPair();
// 3. 将密钥编码为 Base64 字符串
String publicKeyString = Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
String privateKeyString = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());
// 输出密钥字符串
System.out.println("Public Key: " + publicKeyString);
System.out.println("Private Key: " + privateKeyString);
}
public static String generateIdpMetaXML(X509Certificate certificate) throws Exception {
EntityDescriptorBuilder entityDescriptorBuilder = new EntityDescriptorBuilder();
EntityDescriptor entityDescriptor = entityDescriptorBuilder.buildObject();
entityDescriptor.setEntityID(IDP_ENTITY_ID);
IDPSSODescriptorBuilder idpssoDescriptorBuilder = new IDPSSODescriptorBuilder();
IDPSSODescriptor idpssoDescriptor = idpssoDescriptorBuilder.buildObject();
idpssoDescriptor.setWantAuthnRequestsSigned(false);
idpssoDescriptor.addSupportedProtocol(SAMLConstants.SAML20P_NS);
entityDescriptor.getRoleDescriptors().add(idpssoDescriptor);
KeyInfoBuilder keyInfoBuilder = new KeyInfoBuilder();
KeyInfo keyInfo = keyInfoBuilder.buildObject();
X509CertificateBuilder x509CertificateBuilder = new X509CertificateBuilder();
org.opensaml.xmlsec.signature.X509Certificate x509Certificate = x509CertificateBuilder.buildObject();
x509Certificate.setValue(java.util.Base64.getEncoder().encodeToString(certificate.getEncoded()));
X509DataBuilder x509DataBuilder = new X509DataBuilder();
X509Data x509Data = x509DataBuilder.buildObject();
x509Data.getX509Certificates().add(x509Certificate);
keyInfo.getX509Datas().add(x509Data);
KeyDescriptorBuilder keyDescriptorBuilder = new KeyDescriptorBuilder();
KeyDescriptor keyDescriptor = keyDescriptorBuilder.buildObject();
keyDescriptor.setUse(UsageType.SIGNING);
keyDescriptor.setKeyInfo(keyInfo);
idpssoDescriptor.getKeyDescriptors().add(keyDescriptor);
SingleSignOnServiceBuilder singleSignOnServiceBuilder = new SingleSignOnServiceBuilder();
SingleSignOnService singleSignOnService = singleSignOnServiceBuilder.buildObject();
singleSignOnService.setBinding(SAMLConstants.SAML2_POST_BINDING_URI);
singleSignOnService.setLocation(IDP_LOGIN_LOCATION);
idpssoDescriptor.getSingleSignOnServices().add(singleSignOnService);
// output EntityDescriptor
EntityDescriptorMarshaller marshaller = new EntityDescriptorMarshaller();
Element element = marshaller.marshall(entityDescriptor);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.transform(new DOMSource(element), new StreamResult(baos));
// XMLHelper.writeNode(element, baos);
String metaXMLStr = new String(baos.toByteArray());
return metaXMLStr;
}
}
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Map;
import java.util.UUID;
import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
import org.opensaml.core.xml.io.Marshaller;
import org.opensaml.core.xml.schema.XSString;
import org.opensaml.core.xml.schema.impl.XSStringBuilder;
import org.opensaml.saml.common.SAMLVersion;
import org.opensaml.saml.saml2.core.Assertion;
import org.opensaml.saml.saml2.core.Attribute;
import org.opensaml.saml.saml2.core.AttributeStatement;
import org.opensaml.saml.saml2.core.AttributeValue;
import org.opensaml.saml.saml2.core.Audience;
import org.opensaml.saml.saml2.core.AudienceRestriction;
import org.opensaml.saml.saml2.core.AuthnContext;
import org.opensaml.saml.saml2.core.AuthnContextClassRef;
import org.opensaml.saml.saml2.core.AuthnStatement;
import org.opensaml.saml.saml2.core.Conditions;
import org.opensaml.saml.saml2.core.Issuer;
import org.opensaml.saml.saml2.core.NameID;
import org.opensaml.saml.saml2.core.NameIDType;
import org.opensaml.saml.saml2.core.Response;
import org.opensaml.saml.saml2.core.Status;
import org.opensaml.saml.saml2.core.StatusCode;
import org.opensaml.saml.saml2.core.Subject;
import org.opensaml.saml.saml2.core.SubjectConfirmation;
import org.opensaml.saml.saml2.core.SubjectConfirmationData;
import org.opensaml.saml.saml2.core.impl.AssertionBuilder;
import org.opensaml.saml.saml2.core.impl.AttributeBuilder;
import org.opensaml.saml.saml2.core.impl.AttributeStatementBuilder;
import org.opensaml.saml.saml2.core.impl.AudienceBuilder;
import org.opensaml.saml.saml2.core.impl.AudienceRestrictionBuilder;
import org.opensaml.saml.saml2.core.impl.AuthnContextBuilder;
import org.opensaml.saml.saml2.core.impl.AuthnContextClassRefBuilder;
import org.opensaml.saml.saml2.core.impl.AuthnStatementBuilder;
import org.opensaml.saml.saml2.core.impl.ConditionsBuilder;
import org.opensaml.saml.saml2.core.impl.IssuerBuilder;
import org.opensaml.saml.saml2.core.impl.NameIDBuilder;
import org.opensaml.saml.saml2.core.impl.ResponseBuilder;
import org.opensaml.saml.saml2.core.impl.StatusBuilder;
import org.opensaml.saml.saml2.core.impl.StatusCodeBuilder;
import org.opensaml.saml.saml2.core.impl.SubjectBuilder;
import org.opensaml.saml.saml2.core.impl.SubjectConfirmationBuilder;
import org.opensaml.saml.saml2.core.impl.SubjectConfirmationDataBuilder;
import org.opensaml.security.credential.Credential;
import org.opensaml.security.x509.BasicX509Credential;
import org.opensaml.xmlsec.EncryptionConfiguration;
import org.opensaml.xmlsec.SecurityConfigurationSupport;
import org.opensaml.xmlsec.keyinfo.KeyInfoGenerator;
import org.opensaml.xmlsec.keyinfo.KeyInfoGeneratorFactory;
import org.opensaml.xmlsec.keyinfo.KeyInfoGeneratorManager;
import org.opensaml.xmlsec.keyinfo.NamedKeyInfoGeneratorManager;
import org.opensaml.xmlsec.signature.KeyInfo;
import org.opensaml.xmlsec.signature.Signature;
import org.opensaml.xmlsec.signature.impl.SignatureBuilder;
import org.opensaml.xmlsec.signature.support.SignatureConstants;
import org.opensaml.xmlsec.signature.support.Signer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
public class SamlUtils {
private static Logger logger = LoggerFactory.getLogger(SamlUtils.class);
public static Response createSAMLResponse(String samlRequestID, String identifier, String replyUrl, String nameID,
Map<String, String> attributes,BasicX509Credential basicX509Credential) throws Exception {
Assert.hasText(identifier, "identifier can not be blank!");
Assert.hasText(replyUrl, "replyUrl can not be blank!");
Assert.hasText(nameID, "nameID can not be blank!");
// Assert.notEmpty(attributes, "attributes can not be empty!");
logger.info("**********************************SAML INFO**********************************");
logger.info("samlRequestID: " + samlRequestID);
logger.info("identifier: " + identifier);
logger.info("replyUrl: " + replyUrl);
logger.info("nameID: " + nameID);
logger.info("attributes: " + attributes);
logger.info("*****************************************************************************");
// ****************默认参数***************
Instant authenticationTime = Instant.now();
String issuer = Test.IDP_ENTITY_ID;
Integer samlAssertionDays = 2;
// ****************默认参数***************
Signature signature = createSignature(basicX509Credential);
Status status = createStatus();
Issuer responseIssuer = null;
Issuer assertionIssuer = null;
Subject subject = null;
AttributeStatement attributeStatement = null;
if (issuer != null) {
responseIssuer = createIssuer(issuer);
assertionIssuer = createIssuer(issuer);
}
if (attributes != null) {
attributeStatement = createAttributeStatement(attributes);
}
if (nameID != null) {
subject = createSubject(replyUrl, nameID, samlAssertionDays, samlRequestID);
}
AuthnStatement authnStatement = createAuthnStatement(authenticationTime);
Assertion assertion = createAssertion(authenticationTime, subject, assertionIssuer, authnStatement,
attributeStatement, samlAssertionDays, identifier);
Response response = createResponse(authenticationTime, responseIssuer, status, assertion);
if (null != samlRequestID) {
response.setInResponseTo(samlRequestID);
}
// aliyun cloud sso 开启新的校验
response.setDestination(replyUrl);
// id不能以数字开头,所以统一加"id"
response.setID("id" + response.getID());
response.getAssertions().get(0).setID("id" + response.getAssertions().get(0).getID());
// aliyun 两种都可以,aws需要把signature放在assertion里
// response.setSignature(signature);
response.getAssertions().get(0).setSignature(signature);
Marshaller marshaller = XMLObjectProviderRegistrySupport.getMarshallerFactory()
.getMarshaller(response.getElementQName());
marshaller.marshall(response);
if (signature != null) {
Signer.signObject(signature);
}
return response;
}
private static Conditions createConditions(Instant notOnOrAfter, final String audienceUri) {
ConditionsBuilder conditionsBuilder = new ConditionsBuilder();
final Conditions conditions = conditionsBuilder.buildObject();
conditions.setNotOnOrAfter(notOnOrAfter);
AudienceRestrictionBuilder audienceRestrictionBuilder = new AudienceRestrictionBuilder();
final AudienceRestriction audienceRestriction = audienceRestrictionBuilder.buildObject();
AudienceBuilder audienceBuilder = new AudienceBuilder();
final Audience audience = audienceBuilder.buildObject();
audience.setURI(audienceUri);
audienceRestriction.getAudiences().add(audience);
conditions.getAudienceRestrictions().add(audienceRestriction);
return conditions;
}
private static Response createResponse(Instant issueDate, Issuer issuer, Status status, Assertion assertion) {
ResponseBuilder responseBuilder = new ResponseBuilder();
Response response = responseBuilder.buildObject();
response.setID(UUID.randomUUID().toString());
response.setIssueInstant(issueDate);
response.setVersion(SAMLVersion.VERSION_20);
response.setIssuer(issuer);
response.setStatus(status);
response.getAssertions().add(assertion);
return response;
}
private static Assertion createAssertion(Instant issueDate, Subject subject, Issuer issuer,
AuthnStatement authnStatement, AttributeStatement attributeStatement, final Integer samlAssertionDays,
final String identifier) {
AssertionBuilder assertionBuilder = new AssertionBuilder();
Assertion assertion = assertionBuilder.buildObject();
assertion.setID(UUID.randomUUID().toString());
assertion.setIssueInstant(issueDate);
assertion.setSubject(subject);
assertion.setIssuer(issuer);
Instant currentDate = Instant.now();
if (samlAssertionDays != null) {
currentDate = currentDate.plus(samlAssertionDays, ChronoUnit.DAYS);
}
Conditions conditions = createConditions(currentDate, identifier);
assertion.setConditions(conditions);
if (authnStatement != null) {
assertion.getAuthnStatements().add(authnStatement);
}
if (attributeStatement != null) {
assertion.getAttributeStatements().add(attributeStatement);
}
return assertion;
}
private static Issuer createIssuer(final String issuerName) {
// create Issuer object
IssuerBuilder issuerBuilder = new IssuerBuilder();
Issuer issuer = issuerBuilder.buildObject();
issuer.setValue(issuerName);
return issuer;
}
private static Subject createSubject(final String replyUrl, final String nameID, final Integer samlAssertionDays,
String samlRequestID) {
Instant currentDate = Instant.now();
if (samlAssertionDays != null) {
currentDate = currentDate.plus(samlAssertionDays, ChronoUnit.DAYS);
}
// create name element
NameIDBuilder nameIdBuilder = new NameIDBuilder();
NameID nameId = nameIdBuilder.buildObject();
nameId.setValue(nameID);
nameId.setFormat(NameIDType.EMAIL);
SubjectConfirmationDataBuilder dataBuilder = new SubjectConfirmationDataBuilder();
SubjectConfirmationData subjectConfirmationData = dataBuilder.buildObject();
subjectConfirmationData.setNotOnOrAfter(currentDate);
subjectConfirmationData.setRecipient(replyUrl);
if (null != samlRequestID) {
subjectConfirmationData.setInResponseTo(samlRequestID);
}
SubjectConfirmationBuilder subjectConfirmationBuilder = new SubjectConfirmationBuilder();
SubjectConfirmation subjectConfirmation = subjectConfirmationBuilder.buildObject();
subjectConfirmation.setMethod("urn:oasis:names:tc:SAML:2.0:cm:bearer");
subjectConfirmation.setSubjectConfirmationData(subjectConfirmationData);
// create subject element
SubjectBuilder subjectBuilder = new SubjectBuilder();
Subject subject = subjectBuilder.buildObject();
subject.setNameID(nameId);
subject.getSubjectConfirmations().add(subjectConfirmation);
return subject;
}
private static AuthnStatement createAuthnStatement(Instant issueDate) {
// create authcontextclassref object
AuthnContextClassRefBuilder classRefBuilder = new AuthnContextClassRefBuilder();
AuthnContextClassRef classRef = classRefBuilder.buildObject();
// classRef.setAuthnContextClassRef("urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport");
classRef.setURI("urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport");
// create authcontext object
AuthnContextBuilder authContextBuilder = new AuthnContextBuilder();
AuthnContext authnContext = authContextBuilder.buildObject();
authnContext.setAuthnContextClassRef(classRef);
// create authenticationstatement object
AuthnStatementBuilder authStatementBuilder = new AuthnStatementBuilder();
AuthnStatement authnStatement = authStatementBuilder.buildObject();
authnStatement.setAuthnInstant(issueDate);
authnStatement.setAuthnContext(authnContext);
return authnStatement;
}
private static AttributeStatement createAttributeStatement(Map<String, String> attributes) {
// create authenticationstatement object
AttributeStatementBuilder attributeStatementBuilder = new AttributeStatementBuilder();
AttributeStatement attributeStatement = attributeStatementBuilder.buildObject();
AttributeBuilder attributeBuilder = new AttributeBuilder();
if (attributes != null) {
for (Map.Entry<String, String> entry : attributes.entrySet()) {
Attribute attribute = attributeBuilder.buildObject();
attribute.setName(entry.getKey());
// 暂时修改成不支持数组的方式,
XSStringBuilder stringBuilder = new XSStringBuilder();
XSString attributeValue = stringBuilder.buildObject(AttributeValue.DEFAULT_ELEMENT_NAME,
XSString.TYPE_NAME);
attributeValue.setValue(entry.getValue());
attribute.getAttributeValues().add(attributeValue);
attributeStatement.getAttributes().add(attribute);
}
}
return attributeStatement;
}
private static Status createStatus() {
StatusCodeBuilder statusCodeBuilder = new StatusCodeBuilder();
StatusCode statusCode = statusCodeBuilder.buildObject();
statusCode.setValue(StatusCode.SUCCESS);
StatusBuilder statusBuilder = new StatusBuilder();
Status status = statusBuilder.buildObject();
status.setStatusCode(statusCode);
return status;
}
private static Signature createSignature(BasicX509Credential basicX509Credential) throws Exception {
SignatureBuilder builder = new SignatureBuilder();
Signature signature = builder.buildObject();
signature.setSigningCredential(basicX509Credential);
signature.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1);
signature.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
// cloudfare need keyinfo test
signature.setKeyInfo(getKeyInfo(signature.getSigningCredential()));
return signature;
}
private static KeyInfo getKeyInfo(Credential credential) throws Exception {
EncryptionConfiguration secConfiguration = SecurityConfigurationSupport.getGlobalEncryptionConfiguration();
NamedKeyInfoGeneratorManager namedKeyInfoGeneratorManager = secConfiguration.getDataKeyInfoGeneratorManager();
KeyInfoGeneratorManager keyInfoGeneratorManager = namedKeyInfoGeneratorManager.getDefaultManager();
KeyInfoGeneratorFactory keyInfoGeneratorFactory = keyInfoGeneratorManager.getFactory(credential);
KeyInfoGenerator keyInfoGenerator = keyInfoGeneratorFactory.newInstance();
KeyInfo keyInfo = keyInfoGenerator.generate(credential);
// keyInfo.getX509Datas().clear();
return keyInfo;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment