001/*
002 * oauth2-oidc-sdk
003 *
004 * Copyright 2012-2016, Connect2id Ltd and contributors.
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use
007 * this file except in compliance with the License. You may obtain a copy of the
008 * License at
009 *
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software distributed
013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the
015 * specific language governing permissions and limitations under the License.
016 */
017
018package com.nimbusds.oauth2.sdk.assertions.saml2;
019
020
021import java.net.InetAddress;
022import java.net.UnknownHostException;
023import java.util.*;
024
025import com.nimbusds.oauth2.sdk.ParseException;
026import com.nimbusds.oauth2.sdk.SerializeException;
027import com.nimbusds.oauth2.sdk.assertions.AssertionDetails;
028import com.nimbusds.oauth2.sdk.id.Audience;
029import com.nimbusds.oauth2.sdk.id.Identifier;
030import com.nimbusds.oauth2.sdk.id.Issuer;
031import com.nimbusds.oauth2.sdk.id.Subject;
032import com.nimbusds.openid.connect.sdk.claims.ACR;
033import net.jcip.annotations.Immutable;
034import org.apache.commons.collections4.CollectionUtils;
035import org.apache.commons.collections4.MapUtils;
036import org.joda.time.DateTime;
037import org.opensaml.Configuration;
038import org.opensaml.DefaultBootstrap;
039import org.opensaml.common.SAMLObjectBuilder;
040import org.opensaml.saml2.core.*;
041import org.opensaml.xml.ConfigurationException;
042import org.opensaml.xml.XMLObject;
043import org.opensaml.xml.XMLObjectBuilderFactory;
044import org.opensaml.xml.schema.XSString;
045import org.opensaml.xml.schema.impl.XSStringBuilder;
046
047
048/**
049 * SAML 2.0 bearer assertion details for OAuth 2.0 client authentication and
050 * authorisation grants.
051 *
052 * <p>Used for {@link com.nimbusds.oauth2.sdk.SAML2BearerGrant SAML 2.0 bearer
053 * assertion grants}.
054 *
055 * <p>Example SAML 2.0 assertion:
056 *
057 * <pre>
058 * &lt;Assertion IssueInstant="2010-10-01T20:07:34.619Z"
059 *            ID="ef1xsbZxPV2oqjd7HTLRLIBlBb7"
060 *            Version="2.0"
061 *            xmlns="urn:oasis:names:tc:SAML:2.0:assertion"&gt;
062 *     &lt;Issuer&gt;https://saml-idp.example.com&lt;/Issuer&gt;
063 *     &lt;ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"&gt;
064 *         [...omitted for brevity...]
065 *     &lt;/ds:Signature&gt;
066 *     &lt;Subject&gt;
067 *         &lt;NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"&gt;
068 *             [email protected]
069 *         &lt;/NameID&gt;
070 *         &lt;SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"&gt;
071 *             &lt;SubjectConfirmationData NotOnOrAfter="2010-10-01T20:12:34.619Z"
072 *                                      Recipient="https://authz.example.net/token.oauth2"/&gt;
073 *         &lt;/SubjectConfirmation&gt;
074 *     &lt;/Subject&gt;
075 *     &lt;Conditions&gt;
076 *         &lt;AudienceRestriction&gt;
077 *             &lt;Audience&gt;https://saml-sp.example.net&lt;/Audience&gt;
078 *         &lt;/AudienceRestriction&gt;
079 *     &lt;/Conditions&gt;
080 *     &lt;AuthnStatement AuthnInstant="2010-10-01T20:07:34.371Z"&gt;
081 *         &lt;AuthnContext&gt;
082 *             &lt;AuthnContextClassRef&gt;urn:oasis:names:tc:SAML:2.0:ac:classes:X509&lt;/AuthnContextClassRef&gt;
083 *         &lt;/AuthnContext&gt;
084 *     &lt;/AuthnStatement&gt;
085 * &lt;/Assertion&gt;
086 * </pre>
087 *
088 * <p>Related specifications:
089 *
090 * <ul>
091 *     <li>Security Assertion Markup Language (SAML) 2.0 Profile for OAuth 2.0
092 *         Client Authentication and Authorization Grants (RFC 7522), section
093 *         3.
094 * </ul>
095 */
096@Immutable
097public class SAML2AssertionDetails extends AssertionDetails {
098
099
100        /**
101         * The subject format (optional).
102         */
103        private final String subjectFormat;
104
105
106        /**
107         * The subject authentication time (optional).
108         */
109        private final Date subjectAuthTime;
110
111
112        /**
113         * The subject Authentication Context Class Reference (ACR) (optional).
114         */
115        private final ACR subjectACR;
116        
117
118        /**
119         * The time before which this assertion must not be accepted for
120         * processing (optional).
121         */
122        private final Date nbf;
123
124
125        /**
126         * The client IPv4 or IPv6 address (optional).
127         */
128        private final InetAddress clientAddress;
129
130
131        /**
132         * The attribute statement (optional).
133         */
134        private final Map<String,List<String>> attrStatement;
135
136
137        /**
138         * Creates a new SAML 2.0 bearer assertion details instance. The
139         * expiration time is set to five minutes from the current system time.
140         * Generates a default identifier for the assertion. The issue time is
141         * set to the current system time.
142         *
143         * @param issuer   The issuer. Must not be {@code null}.
144         * @param subject  The subject. Must not be {@code null}.
145         * @param audience The audience, typically the URI of the authorisation
146         *                 server's token endpoint. Must not be {@code null}.
147         */
148        public SAML2AssertionDetails(final Issuer issuer,
149                                     final Subject subject,
150                                     final Audience audience) {
151
152                this(issuer, subject, null, null, null, audience.toSingleAudienceList(),
153                        new Date(new Date().getTime() + 5*60*1000L), null, new Date(),
154                        new Identifier(), null, null);
155        }
156
157
158        /**
159         * Creates a new SAML 2.0 bearer assertion details instance.
160         *
161         * @param issuer          The issuer. Must not be {@code null}.
162         * @param subject         The subject. Must not be {@code null}.
163         * @param subjectFormat   The subject format, {@code null} if not
164         *                        specified.
165         * @param subjectAuthTime The subject authentication time, {@code null}
166         *                        if not specified.
167         * @param subjectACR      The subject Authentication Context Class
168         *                        Reference (ACR), {@code null} if not
169         *                        specified.
170         * @param audience        The audience, typically including the URI of the
171         *                        authorisation server's token endpoint. Must not be
172         *                        {@code null}.
173         * @param exp             The expiration time. Must not be {@code null}.
174         * @param nbf             The time before which the assertion must not
175         *                        be accepted for processing, {@code null} if
176         *                        not specified.
177         * @param iat             The time at which the assertion was issued.
178         *                        Must not be {@code null}.
179         * @param id              Unique identifier for the assertion. Must not
180         *                        be {@code null}.
181         * @param clientAddress   The client address, {@code null} if not
182         *                        specified.
183         * @param attrStatement   The attribute statement (in simplified form),
184         *                        {@code null} if not specified.
185         */
186        public SAML2AssertionDetails(final Issuer issuer,
187                                     final Subject subject,
188                                     final String subjectFormat,
189                                     final Date subjectAuthTime,
190                                     final ACR subjectACR,
191                                     final List<Audience> audience,
192                                     final Date exp,
193                                     final Date nbf,
194                                     final Date iat,
195                                     final Identifier id,
196                                     final InetAddress clientAddress,
197                                     final Map<String,List<String>> attrStatement) {
198
199                super(issuer, subject, audience, iat, exp, id);
200
201                if (iat == null) {
202                        throw new IllegalArgumentException("The issue time must not be null");
203                }
204
205                if (id == null) {
206                        throw new IllegalArgumentException("The assertion identifier must not be null");
207                }
208
209                this.subjectFormat = subjectFormat;
210                this.subjectAuthTime = subjectAuthTime;
211                this.subjectACR = subjectACR;
212                this.clientAddress = clientAddress;
213                this.nbf = nbf;
214                this.attrStatement = attrStatement;
215        }
216
217
218        /**
219         * Returns the optional subject format.
220         *
221         * @return The subject format, {@code null} if not specified.
222         */
223        public String getSubjectFormat() {
224                return subjectFormat;
225        }
226
227
228        /**
229         * Returns the optional subject authentication time.
230         *
231         * @return The subject authentication time, {@code null} if not
232         *         specified.
233         */
234        public Date getSubjectAuthenticationTime() {
235                return subjectAuthTime;
236        }
237
238
239        /**
240         * Returns the optional subject Authentication Context Class Reference
241         * (ACR).
242         *
243         * @return The subject ACR, {@code null} if not specified.
244         */
245        public ACR getSubjectACR() {
246                return subjectACR;
247        }
248
249
250        /**
251         * Returns the optional not-before time.
252         *
253         * @return The not-before time, {@code null} if not specified.
254         */
255        public Date getNotBeforeTime() {
256                return nbf;
257        }
258
259
260        /**
261         * Returns the optional client address to which this assertion is
262         * bound.
263         *
264         * @return The client address, {@code null} if not specified.
265         */
266        public InetAddress getClientInetAddress() {
267                return clientAddress;
268        }
269
270
271        /**
272         * Returns the optional attribute statement.
273         *
274         * @return The attribute statement (in simplified form), {@code null}
275         *         if not specified.
276         */
277        public Map<String, List<String>> getAttributeStatement() {
278                return attrStatement;
279        }
280
281
282        /**
283         * Returns a SAML 2.0 assertion (unsigned) representation of this
284         * assertion details instance.
285         *
286         * @return The SAML 2.0 assertion (with no signature element).
287         *
288         * @throws SerializeException If serialisation failed.
289         */
290        public Assertion toSAML2Assertion()
291                throws SerializeException {
292
293                try {
294                        DefaultBootstrap.bootstrap();
295                } catch (ConfigurationException e) {
296                        throw new SerializeException(e.getMessage(), e);
297                }
298
299                final XMLObjectBuilderFactory builderFactory = Configuration.getBuilderFactory();
300
301                // Top level assertion element
302                SAMLObjectBuilder<Assertion> assertionBuilder = (SAMLObjectBuilder<Assertion>) builderFactory.getBuilder(Assertion.DEFAULT_ELEMENT_NAME);
303
304                Assertion a = assertionBuilder.buildObject();
305                a.setID(getID().getValue());
306                a.setIssueInstant(new DateTime(getIssueTime()));
307
308                // Issuer
309                SAMLObjectBuilder<org.opensaml.saml2.core.Issuer> issuerBuilder = (SAMLObjectBuilder<org.opensaml.saml2.core.Issuer>) builderFactory.getBuilder(org.opensaml.saml2.core.Issuer.DEFAULT_ELEMENT_NAME);
310                org.opensaml.saml2.core.Issuer iss = issuerBuilder.buildObject();
311                iss.setValue(getIssuer().getValue());
312                a.setIssuer(iss);
313
314                // Conditions
315                SAMLObjectBuilder<Conditions> conditionsBuilder = (SAMLObjectBuilder<Conditions>) builderFactory.getBuilder(Conditions.DEFAULT_ELEMENT_NAME);
316                Conditions conditions = conditionsBuilder.buildObject();
317
318                // Audience restriction
319                SAMLObjectBuilder<AudienceRestriction> audRestrictionBuilder = (SAMLObjectBuilder<AudienceRestriction>) builderFactory.getBuilder(AudienceRestriction.DEFAULT_ELEMENT_NAME);
320                AudienceRestriction audRestriction = audRestrictionBuilder.buildObject();
321
322                // ... with single audience - the authz server
323                SAMLObjectBuilder<org.opensaml.saml2.core.Audience> audBuilder = (SAMLObjectBuilder<org.opensaml.saml2.core.Audience>) builderFactory.getBuilder(org.opensaml.saml2.core.Audience.DEFAULT_ELEMENT_NAME);
324                for (Audience audItem: getAudience()) {
325                        org.opensaml.saml2.core.Audience aud = audBuilder.buildObject();
326                        aud.setAudienceURI(audItem.getValue());
327                        audRestriction.getAudiences().add(aud);
328                }
329                conditions.getAudienceRestrictions().add(audRestriction);
330
331                a.setConditions(conditions);
332
333
334                // Subject elements
335                SAMLObjectBuilder<org.opensaml.saml2.core.Subject> subBuilder = (SAMLObjectBuilder<org.opensaml.saml2.core.Subject>) builderFactory.getBuilder(org.opensaml.saml2.core.Subject.DEFAULT_ELEMENT_NAME);
336                org.opensaml.saml2.core.Subject sub = subBuilder.buildObject();
337
338                SAMLObjectBuilder<NameID> subIDBuilder = (SAMLObjectBuilder<NameID>) builderFactory.getBuilder(NameID.DEFAULT_ELEMENT_NAME);
339                NameID nameID = subIDBuilder.buildObject();
340                nameID.setFormat(subjectFormat);
341                nameID.setValue(getSubject().getValue());
342                sub.setNameID(nameID);
343
344                SAMLObjectBuilder<SubjectConfirmation> subCmBuilder = (SAMLObjectBuilder<SubjectConfirmation>) builderFactory.getBuilder(SubjectConfirmation.DEFAULT_ELEMENT_NAME);
345                SubjectConfirmation subCm = subCmBuilder.buildObject();
346                subCm.setMethod(SubjectConfirmation.METHOD_BEARER);
347
348                SAMLObjectBuilder<SubjectConfirmationData> subCmDataBuilder= (SAMLObjectBuilder<SubjectConfirmationData>) builderFactory.getBuilder(SubjectConfirmationData.DEFAULT_ELEMENT_NAME);
349                SubjectConfirmationData subCmData = subCmDataBuilder.buildObject();
350                subCmData.setNotOnOrAfter(new DateTime(getExpirationTime()));
351                subCmData.setNotBefore(getNotBeforeTime() != null ? new DateTime(getNotBeforeTime()) : null);
352                subCmData.setRecipient(getAudience().get(0).getValue()); // recipient is single-valued
353
354                if (clientAddress != null) {
355                        subCmData.setAddress(clientAddress.getHostAddress());
356                }
357
358                subCm.setSubjectConfirmationData(subCmData);
359
360                sub.getSubjectConfirmations().add(subCm);
361
362                a.setSubject(sub);
363
364                // Auth time and class?
365                if (subjectAuthTime != null || subjectACR != null) {
366
367                        SAMLObjectBuilder<AuthnStatement> authnStmtBuilder = (SAMLObjectBuilder<AuthnStatement>) builderFactory.getBuilder(AuthnStatement.DEFAULT_ELEMENT_NAME);
368                        AuthnStatement authnStmt = authnStmtBuilder.buildObject();
369
370                        if (subjectAuthTime != null) {
371                                authnStmt.setAuthnInstant(new DateTime(subjectAuthTime));
372                        }
373
374                        if (subjectACR != null) {
375                                SAMLObjectBuilder<AuthnContext> authnCtxBuilder = (SAMLObjectBuilder<AuthnContext>) builderFactory.getBuilder(AuthnContext.DEFAULT_ELEMENT_NAME);
376                                AuthnContext authnCtx = authnCtxBuilder.buildObject();
377                                SAMLObjectBuilder<AuthnContextClassRef> acrBuilder = (SAMLObjectBuilder<AuthnContextClassRef>) builderFactory.getBuilder(AuthnContextClassRef.DEFAULT_ELEMENT_NAME);
378                                AuthnContextClassRef acr = acrBuilder.buildObject();
379                                acr.setAuthnContextClassRef(subjectACR.getValue());
380                                authnCtx.setAuthnContextClassRef(acr);
381                                authnStmt.setAuthnContext(authnCtx);
382                        }
383
384                        a.getAuthnStatements().add(authnStmt);
385                }
386
387                // Attributes?
388                if (MapUtils.isNotEmpty(attrStatement)) {
389
390                        SAMLObjectBuilder<AttributeStatement> attrContainerBuilder = (SAMLObjectBuilder<AttributeStatement>) builderFactory.getBuilder(AttributeStatement.DEFAULT_ELEMENT_NAME);
391                        AttributeStatement attrSet = attrContainerBuilder.buildObject();
392
393                        SAMLObjectBuilder<Attribute> attrBuilder = (SAMLObjectBuilder<Attribute>) builderFactory.getBuilder(Attribute.DEFAULT_ELEMENT_NAME);
394
395                        for (Map.Entry<String,List<String>> entry: attrStatement.entrySet()) {
396
397                                Attribute attr = attrBuilder.buildObject();
398                                attr.setName(entry.getKey());
399
400                                XSStringBuilder stringBuilder = (XSStringBuilder) Configuration.getBuilderFactory().getBuilder(XSString.TYPE_NAME);
401
402                                for (String v: entry.getValue()) {
403                                        XSString stringValue = stringBuilder.buildObject(AttributeValue.DEFAULT_ELEMENT_NAME, XSString.TYPE_NAME);
404                                        stringValue.setValue(v);
405                                        attr.getAttributeValues().add(stringValue);
406                                }
407
408                                attrSet.getAttributes().add(attr);
409                        }
410
411                        a.getAttributeStatements().add(attrSet);
412                }
413
414                return a;
415        }
416
417
418        /**
419         * Parses a SAML 2.0 bearer assertion details instance from the
420         * specified assertion object.
421         *
422         * @param assertion The assertion. Must not be {@code null}.
423         *
424         * @return The SAML 2.0 bearer assertion details.
425         *
426         * @throws ParseException If the assertion couldn't be parsed to a
427         *                        SAML 2.0 bearer assertion details instance.
428         */
429        public static SAML2AssertionDetails parse(final Assertion assertion)
430                throws ParseException {
431
432                // Assertion > Issuer
433                if (assertion.getIssuer() == null) {
434                        throw new ParseException("Missing Assertion Issuer element");
435                }
436
437                final Issuer issuer = new Issuer(assertion.getIssuer().getValue());
438
439                // Assertion > Subject
440                if (assertion.getSubject() == null) {
441                        throw new ParseException("Missing Assertion Subject element");
442                }
443
444                if (assertion.getSubject().getNameID() == null) {
445                        throw new ParseException("Missing Assertion Subject NameID element");
446                }
447
448                // Assertion > Subject > NameID
449                final Subject subject = new Subject(assertion.getSubject().getNameID().getValue());
450
451                // Assertion > Subject > NameID : Format
452                final String subjectFormat = assertion.getSubject().getNameID().getFormat();
453
454                // Assertion > AuthnStatement : AuthnInstant
455                Date subjectAuthTime = null;
456
457                // Assertion > AuthnStatement > AuthnContext > AuthnContextClassRef
458                ACR subjectACR = null;
459
460                if (CollectionUtils.isNotEmpty(assertion.getAuthnStatements())) {
461
462                        for (AuthnStatement authStmt: assertion.getAuthnStatements()) {
463
464                                if (authStmt == null) {
465                                        continue; // skip
466                                }
467
468                                if (authStmt.getAuthnInstant() != null) {
469                                        subjectAuthTime = authStmt.getAuthnInstant().toDate();
470                                }
471
472                                if (authStmt.getAuthnContext() != null && authStmt.getAuthnContext().getAuthnContextClassRef() != null) {
473                                        subjectACR = new ACR(authStmt.getAuthnContext().getAuthnContextClassRef().getAuthnContextClassRef());
474                                }
475                        }
476                }
477
478                List<SubjectConfirmation> subCms = assertion.getSubject().getSubjectConfirmations();
479
480                if (CollectionUtils.isEmpty(subCms)) {
481                        throw new ParseException("Missing SubjectConfirmation element");
482                }
483
484                // Assertion > Subject > SubjectConfirmation : Method
485                boolean bearerMethodFound = false;
486                for (SubjectConfirmation subCm: subCms) {
487                        if (SubjectConfirmation.METHOD_BEARER.equals(subCm.getMethod())) {
488                                bearerMethodFound = true;
489                                break;
490                        }
491                }
492
493                if (! bearerMethodFound) {
494                        throw new ParseException("Missing SubjectConfirmation Method " + SubjectConfirmation.METHOD_BEARER + " attribute");
495                }
496
497                Conditions conditions = assertion.getConditions();
498
499                if (conditions == null) {
500                        throw new ParseException("Missing Conditions element");
501                }
502
503                List<AudienceRestriction> audRestrictions = conditions.getAudienceRestrictions();
504
505                if (CollectionUtils.isEmpty(audRestrictions)) {
506                        throw new ParseException("Missing AudienceRestriction element");
507                }
508
509                // Assertion > Conditions > AudienceRestriction > Audience
510                final Set<Audience> audSet = new HashSet<>(); // ensure no duplicates
511
512                for (AudienceRestriction audRestriction: audRestrictions) {
513
514                        if (CollectionUtils.isEmpty(audRestriction.getAudiences())) {
515                                continue; // skip
516                        }
517
518                        for (org.opensaml.saml2.core.Audience aud: audRestriction.getAudiences()) {
519                                audSet.add(new Audience(aud.getAudienceURI()));
520                        }
521                }
522
523                // Optional recipient in
524                // Assertion > Subject > SubjectConfirmation > SubjectConfirmationData
525                for (SubjectConfirmation subCm: subCms) {
526
527                        if (subCm.getSubjectConfirmationData() == null) {
528                                continue; // skip
529                        }
530
531                        if (subCm.getSubjectConfirmationData().getRecipient() == null) {
532                                throw new ParseException("Missing SubjectConfirmationData Recipient attribute");
533                        }
534
535                        audSet.add(new Audience(subCm.getSubjectConfirmationData().getRecipient()));
536                }
537
538                // Set expiration and not-before times, try first in
539                // Assertion > Conditions
540                Date exp = conditions.getNotOnOrAfter() != null ? conditions.getNotOnOrAfter().toDate() : null;
541                Date nbf = conditions.getNotBefore() != null ? conditions.getNotBefore().toDate() : null;
542                if (exp == null) {
543                        // Try in Assertion > Subject > SubjectConfirmation > SubjectConfirmationData
544                        for (SubjectConfirmation subCm: subCms) {
545                                if (subCm.getSubjectConfirmationData() == null) {
546                                        continue; // skip
547                                }
548
549                                exp = subCm.getSubjectConfirmationData().getNotOnOrAfter() != null ?
550                                        subCm.getSubjectConfirmationData().getNotOnOrAfter().toDate()
551                                        : null;
552
553                                nbf = subCm.getSubjectConfirmationData().getNotBefore() != null ?
554                                        subCm.getSubjectConfirmationData().getNotBefore().toDate()
555                                        : null;
556                        }
557                }
558
559                // Assertion : ID
560                if (assertion.getID() == null) {
561                        throw new ParseException("Missing Assertion ID attribute");
562                }
563
564                final Identifier id = new Identifier(assertion.getID());
565
566                // Assertion : IssueInstant
567                if (assertion.getIssueInstant() == null) {
568                        throw new ParseException("Missing Assertion IssueInstant attribute");
569                }
570
571                final Date iat = assertion.getIssueInstant().toDate();
572
573                // Assertion > Subject > SubjectConfirmation > SubjectConfirmationData > Address
574                InetAddress clientAddress = null;
575
576                for (SubjectConfirmation subCm: subCms) {
577                        if (subCm.getSubjectConfirmationData() != null && subCm.getSubjectConfirmationData().getAddress() != null) {
578                                try {
579                                        clientAddress = InetAddress.getByName(subCm.getSubjectConfirmationData().getAddress());
580                                } catch (UnknownHostException e) {
581                                        throw new ParseException("Invalid Address: " + e.getMessage(), e);
582                                }
583                        }
584                }
585
586                // Assertion > AttributeStatement > Attribute (: Name, > AttributeValue)
587                Map<String,List<String>> attrStatement = null;
588
589                if (CollectionUtils.isNotEmpty(assertion.getAttributeStatements())) {
590
591                        attrStatement = new HashMap<>();
592
593                        for (AttributeStatement attrStmt: assertion.getAttributeStatements()) {
594                                if (attrStmt == null) {
595                                        continue; // skip
596                                }
597
598                                for (Attribute attr: attrStmt.getAttributes()) {
599                                        String name = attr.getName();
600                                        List<String> values = new LinkedList<>();
601                                        for (XMLObject v: attr.getAttributeValues()) {
602                                                values.add(v.getDOM().getTextContent());
603                                        }
604                                        attrStatement.put(name, values);
605                                }
606                        }
607                }
608
609
610                return new SAML2AssertionDetails(issuer, subject, subjectFormat, subjectAuthTime, subjectACR,
611                        new ArrayList<>(audSet), exp, nbf, iat, id, clientAddress, attrStatement);
612        }
613}