This is an automated email from the ASF dual-hosted git repository.
lmccay pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/knox.git
The following commit(s) were added to refs/heads/master by this push:
new 5d410895d KNOX-3347 - Introduce TokenExchangePrincipal for extending
Act claim … (#1262)
5d410895d is described below
commit 5d410895d452a6fe8b270a59ffce8d3a48237160
Author: lmccay <[email protected]>
AuthorDate: Tue Jun 16 11:12:59 2026 -0400
KNOX-3347 - Introduce TokenExchangePrincipal for extending Act claim …
(#1262)
* KNOX-3347 - Introduce TokenExchangePrincipal for extending Act claim for
token_exchange
---
.../filter/AbstractIdentityAssertionFilter.java | 23 ++++
.../federation/jwt/filter/JWTFederationFilter.java | 150 ++++++++++++++++++++-
.../apache/knox/gateway/security/SubjectUtils.java | 17 +++
.../gateway/security/TokenExchangePrincipal.java | 122 +++++++++++++++++
.../security/TokenExchangePrincipalImpl.java | 108 +++++++++++++++
5 files changed, 416 insertions(+), 4 deletions(-)
diff --git
a/gateway-provider-identity-assertion-common/src/main/java/org/apache/knox/gateway/identityasserter/common/filter/AbstractIdentityAssertionFilter.java
b/gateway-provider-identity-assertion-common/src/main/java/org/apache/knox/gateway/identityasserter/common/filter/AbstractIdentityAssertionFilter.java
index 4c212a534..81efb1511 100644
---
a/gateway-provider-identity-assertion-common/src/main/java/org/apache/knox/gateway/identityasserter/common/filter/AbstractIdentityAssertionFilter.java
+++
b/gateway-provider-identity-assertion-common/src/main/java/org/apache/knox/gateway/identityasserter/common/filter/AbstractIdentityAssertionFilter.java
@@ -51,6 +51,7 @@ import org.apache.knox.gateway.security.GroupPrincipal;
import org.apache.knox.gateway.security.ImpersonatedPrincipal;
import org.apache.knox.gateway.security.PrimaryPrincipal;
import org.apache.knox.gateway.security.SubjectUtils;
+import org.apache.knox.gateway.security.TokenExchangePrincipal;
import org.apache.knox.gateway.security.TokenIdPrincipal;
public abstract class AbstractIdentityAssertionFilter extends
@@ -106,6 +107,23 @@ public abstract class AbstractIdentityAssertionFilter
extends
throw new IllegalStateException("Required Subject Missing");
}
+ // RFC 8693: Check if this is a token exchange request
+ // For token exchange, we need to apply local policy mapping to the
subject identity
+ // BEFORE using it for impersonation. This ensures topology
configuration takes precedence.
+ TokenExchangePrincipal tokenExchangePrincipal =
SubjectUtils.getTokenExchangePrincipal(currentSubject);
+ if (tokenExchangePrincipal != null) {
+ // Get the subject identity from token exchange
+ String tokenExchangeSubject =
tokenExchangePrincipal.getSubjectPrincipalName();
+
+ // Apply local policy mapping to the subject identity
+ // This allows topology configuration to map external identities to
local ones
+ String mappedTokenExchangeSubject =
mapUserPrincipal(tokenExchangeSubject);
+
+ // Use the mapped subject as the identity to impersonate
+ // This respects local policy while honoring the token exchange
semantics
+ mappedPrincipalName = mappedTokenExchangeSubject;
+ }
+
String primaryPrincipalName =
SubjectUtils.getPrimaryPrincipalName(currentSubject);
if (primaryPrincipalName != null) {
if (!primaryPrincipalName.equals(mappedPrincipalName)) {
@@ -153,6 +171,11 @@ public abstract class AbstractIdentityAssertionFilter
extends
final Set<ActorChainPrincipal> actorChainPrincipals =
SubjectUtils.getActorChainPrincipal(currentSubject, subject);
subject.getPrincipals().addAll(actorChainPrincipals);
+ // RFC 8693 Token Exchange: Preserve TokenExchangePrincipal for
audit trail
+ if (tokenExchangePrincipal != null) {
+ subject.getPrincipals().add(tokenExchangePrincipal);
+ }
+
doAs(request, response, chain, subject);
}
else {
diff --git
a/gateway-provider-security-jwt/src/main/java/org/apache/knox/gateway/provider/federation/jwt/filter/JWTFederationFilter.java
b/gateway-provider-security-jwt/src/main/java/org/apache/knox/gateway/provider/federation/jwt/filter/JWTFederationFilter.java
index 3979f0b02..557e81571 100644
---
a/gateway-provider-security-jwt/src/main/java/org/apache/knox/gateway/provider/federation/jwt/filter/JWTFederationFilter.java
+++
b/gateway-provider-security-jwt/src/main/java/org/apache/knox/gateway/provider/federation/jwt/filter/JWTFederationFilter.java
@@ -21,7 +21,11 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.knox.gateway.i18n.messages.MessagesFactory;
import org.apache.knox.gateway.provider.federation.jwt.JWTMessages;
+import org.apache.knox.gateway.security.ActorChainPrincipalImpl;
import org.apache.knox.gateway.security.PrimaryPrincipal;
+import org.apache.knox.gateway.security.TokenExchangePrincipal;
+import org.apache.knox.gateway.security.TokenExchangePrincipalImpl;
+import org.apache.knox.gateway.services.security.token.TokenUtils;
import org.apache.knox.gateway.services.security.token.UnknownTokenException;
import org.apache.knox.gateway.services.security.token.impl.JWT;
import org.apache.knox.gateway.services.security.token.impl.JWTToken;
@@ -40,11 +44,13 @@ import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
+import java.security.Principal;
import java.text.ParseException;
import java.util.Base64;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
+import java.util.Map;
import java.util.Set;
import static java.nio.charset.StandardCharsets.UTF_8;
@@ -65,6 +71,7 @@ public class JWTFederationFilter extends AbstractJWTFilter {
public static final String REFRESH_TOKEN_PARAM = "refresh_token";
public static final String TOKEN_EXCHANGE =
"urn:ietf:params:oauth:grant-type:token-exchange";
public static final String SUBJECT_TOKEN = "subject_token";
+ public static final String ACTOR_TOKEN = "actor_token";
public static final String CLIENT_ASSERTION_JWT_BEARER =
"urn:ietf:params:oauth:client-assertion-type:jwt-bearer";
public static final String CLIENT_ASSERTION_TYPE = "client_assertion_type";
public static final String CLIENT_ASSERTION = "client_assertion";
@@ -172,6 +179,15 @@ public class JWTFederationFilter extends AbstractJWTFilter
{
}
}
+ // RFC 8693: Check if this is a token exchange request
+ HttpServletRequest httpRequest = (HttpServletRequest) request;
+ String grantType = httpRequest.getParameter(GRANT_TYPE);
+ if (TOKEN_EXCHANGE.equals(grantType)) {
+ // Handle RFC 8693 token exchange with subject_token and actor_token
+ handleTokenExchange(httpRequest, (HttpServletResponse) response, chain);
+ return;
+ }
+
Pair<TokenType, String> wireToken = null;
try {
wireToken = getWireToken(request);
@@ -186,8 +202,8 @@ public class JWTFederationFilter extends AbstractJWTFilter {
if (TokenType.JWT.equals(tokenType)) {
try {
- JWT token = new JWTToken(tokenValue);
- if (validateToken((HttpServletRequest) request,
(HttpServletResponse) response, chain, token)) {
+ JWT token = parseAndValidateJWT((HttpServletRequest) request,
(HttpServletResponse) response, chain, tokenValue);
+ if (token != null) {
Subject subject = createSubjectFromToken(token);
continueWithEstablishedSecurityContext(subject,
(HttpServletRequest) request, (HttpServletResponse) response, chain);
}
@@ -383,8 +399,8 @@ public class JWTFederationFilter extends AbstractJWTFilter {
final List<Cookie> relevantCookies =
CookieUtils.getCookiesForName(request, cookieName);
for (Cookie ssoCookie : relevantCookies) {
try {
- final JWT token = new JWTToken(ssoCookie.getValue());
- if (validateToken(request, response, chain, token)) {
+ final JWT token = parseAndValidateJWT(request, response, chain,
ssoCookie.getValue());
+ if (token != null) {
final Subject subject = createSubjectFromToken(token);
continueWithEstablishedSecurityContext(subject, request, response,
chain);
// we found a valid cookie we don't need to keep checking anymore
@@ -405,6 +421,132 @@ public class JWTFederationFilter extends
AbstractJWTFilter {
return false;
}
+ /**
+ * Handle RFC 8693 token exchange flow.
+ *
+ * <p>This method validates both the subject_token and actor_token
parameters,
+ * creates a TokenExchangePrincipal with the identity information from both
tokens,
+ * and establishes a Subject with the actor as the PrimaryPrincipal.</p>
+ *
+ * <p>The TokenExchangePrincipal signals to the identity assertion layer that
+ * impersonation should be established with the subject as the
ImpersonatedPrincipal.</p>
+ *
+ * @param request the HTTP request containing subject_token and actor_token
parameters
+ * @param response the HTTP response
+ * @param chain the filter chain
+ * @throws IOException if an I/O error occurs
+ * @throws ServletException if a servlet error occurs
+ */
+ private void handleTokenExchange(HttpServletRequest request,
HttpServletResponse response, FilterChain chain)
+ throws IOException, ServletException {
+ // Extract subject_token (required)
+ String subjectTokenValue = request.getParameter(SUBJECT_TOKEN);
+ if (subjectTokenValue == null || subjectTokenValue.isEmpty()) {
+ handleValidationError(request, response,
HttpServletResponse.SC_BAD_REQUEST,
+ "RFC 8693 token exchange requires subject_token parameter");
+ return;
+ }
+
+ // Extract actor_token (required for proper token exchange)
+ String actorTokenValue = request.getParameter(ACTOR_TOKEN);
+ if (actorTokenValue == null || actorTokenValue.isEmpty()) {
+ handleValidationError(request, response,
HttpServletResponse.SC_BAD_REQUEST,
+ "RFC 8693 token exchange requires actor_token parameter");
+ return;
+ }
+
+ try {
+ // Parse and validate subject_token
+ JWT subjectToken = parseAndValidateJWT(request, response, chain,
subjectTokenValue);
+ if (subjectToken == null) {
+ // Validation failed, error response already sent
+ return;
+ }
+
+ // Parse and validate actor_token
+ JWT actorToken = parseAndValidateJWT(request, response, chain,
actorTokenValue);
+ if (actorToken == null) {
+ // Validation failed, error response already sent
+ return;
+ }
+
+ // Create Subject with actor as PrimaryPrincipal and
TokenExchangePrincipal
+ Subject subject = createSubjectForTokenExchange(subjectToken,
actorToken);
+
+ continueWithEstablishedSecurityContext(subject, request, response,
chain);
+
+ } catch (ParseException e) {
+ LOGGER.failedToParsePasscodeToken(e);
+ handleValidationError(request, response,
HttpServletResponse.SC_UNAUTHORIZED,
+ "Failed to parse token in token exchange: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Parse and validate a JWT token.
+ *
+ * @param request the HTTP request
+ * @param response the HTTP response
+ * @param chain the filter chain
+ * @param tokenValue the JWT string to parse
+ * @return the parsed and validated JWT, or null if validation failed
+ * @throws ParseException if the JWT cannot be parsed
+ * @throws IOException if an I/O error occurs during validation
+ * @throws ServletException if a servlet error occurs during validation
+ */
+ private JWT parseAndValidateJWT(HttpServletRequest request,
HttpServletResponse response,
+ FilterChain chain, String tokenValue)
+ throws ParseException, IOException, ServletException {
+ JWT token = new JWTToken(tokenValue);
+ if (validateToken(request, response, chain, token)) {
+ return token;
+ }
+ // Validation failed - error response already sent by validateToken
+ return null;
+ }
+
+ /**
+ * Create a Subject for RFC 8693 token exchange with proper principal setup.
+ *
+ * @param subjectToken the validated subject token
+ * @param actorToken the validated actor token
+ * @return a Subject configured for token exchange
+ */
+ private Subject createSubjectForTokenExchange(JWT subjectToken, JWT
actorToken) {
+ // Extract identities from the tokens
+ String subjectPrincipalName = subjectToken.getSubject();
+ String subjectIssuer = subjectToken.getIssuer();
+ String actorPrincipalName = actorToken.getSubject();
+ String actorIssuer = actorToken.getIssuer();
+ // Create principals for the Subject
+ // PrimaryPrincipal is the ACTOR (the authenticated party)
+ PrimaryPrincipal primaryPrincipal =
+ new PrimaryPrincipal(actorPrincipalName);
+
+ // TokenExchangePrincipal carries metadata for identity assertion layer
+ TokenExchangePrincipal tokenExchangePrincipal =
+ new TokenExchangePrincipalImpl(
+ subjectPrincipalName, subjectIssuer, actorPrincipalName,
actorIssuer);
+
+ // Extract actor chain from subject_token (if present) using existing logic
+ List<Map<String, Object>> actorChain =
+ TokenUtils.extractActorChain(subjectToken);
+
+ // Create Subject with all necessary principals
+ Set<Principal> principals = new HashSet<>();
+ principals.add(primaryPrincipal);
+ principals.add(tokenExchangePrincipal);
+
+ // Add ActorChainPrincipal if actor chain exists in subject_token
+ if (!actorChain.isEmpty()) {
+ principals.add(new ActorChainPrincipalImpl(actorChain));
+ }
+
+ @SuppressWarnings("rawtypes")
+ HashSet emptySet = new HashSet();
+ return new Subject(true, principals, emptySet, emptySet);
+ }
+
@Override
protected void handleValidationError(HttpServletRequest request,
HttpServletResponse response, int status,
String error) throws IOException {
diff --git
a/gateway-spi/src/main/java/org/apache/knox/gateway/security/SubjectUtils.java
b/gateway-spi/src/main/java/org/apache/knox/gateway/security/SubjectUtils.java
index 11db9113f..9b6b50a62 100644
---
a/gateway-spi/src/main/java/org/apache/knox/gateway/security/SubjectUtils.java
+++
b/gateway-spi/src/main/java/org/apache/knox/gateway/security/SubjectUtils.java
@@ -105,4 +105,21 @@ public class SubjectUtils {
public static Set<ActorChainPrincipal> getActorChainPrincipal(Subject
currentSubject, Subject subject) {
return currentSubject.getPrincipals(ActorChainPrincipal.class);
}
+
+ /**
+ * Get the TokenExchangePrincipal from the subject if present.
+ *
+ * <p>This is used to detect when an RFC 8693 token exchange has occurred
+ * and to extract the subject and actor identities.</p>
+ *
+ * @param subject the subject to check
+ * @return the TokenExchangePrincipal if present, null otherwise
+ */
+ public static TokenExchangePrincipal getTokenExchangePrincipal(Subject
subject) {
+ if (subject == null) {
+ return null;
+ }
+ Set<TokenExchangePrincipal> principals =
subject.getPrincipals(TokenExchangePrincipal.class);
+ return principals.isEmpty() ? null : principals.iterator().next();
+ }
}
diff --git
a/gateway-spi/src/main/java/org/apache/knox/gateway/security/TokenExchangePrincipal.java
b/gateway-spi/src/main/java/org/apache/knox/gateway/security/TokenExchangePrincipal.java
new file mode 100644
index 000000000..835fa1450
--- /dev/null
+++
b/gateway-spi/src/main/java/org/apache/knox/gateway/security/TokenExchangePrincipal.java
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.security;
+
+import java.security.Principal;
+
+/**
+ * Principal that represents an RFC 8693 token exchange operation.
+ *
+ * <p>This principal carries metadata about both the subject and actor tokens
+ * through the authentication and identity assertion pipeline. It signals to
+ * downstream layers that a token exchange has occurred and provides the
+ * necessary information to establish proper impersonation semantics.</p>
+ *
+ * <p>In RFC 8693 token exchange:</p>
+ * <ul>
+ * <li><b>Subject Token</b>: Represents the identity of the party on behalf
+ * of whom the request is being made (will become
ImpersonatedPrincipal)</li>
+ * <li><b>Actor Token</b>: Represents the identity of the acting party who
+ * is authorized to act (will become PrimaryPrincipal)</li>
+ * </ul>
+ *
+ * <p>This principal is added to the Subject during authentication/federation
+ * and is used by the identity assertion layer to establish the correct
+ * impersonation relationship using Subject.doAs().</p>
+ *
+ * <p>Example usage flow:</p>
+ * <pre>
+ * // In JWTFederationFilter (authentication layer):
+ * JWT subjectToken = validateSubjectToken(request);
+ * JWT actorToken = validateActorToken(request);
+ * TokenExchangePrincipal tep = new TokenExchangePrincipalImpl(
+ * subjectToken.getSubject(), subjectToken.getIssuer(),
+ * actorToken.getSubject(), actorToken.getIssuer()
+ * );
+ * subject.getPrincipals().add(tep);
+ *
+ * // In AbstractIdentityAssertionFilter (identity assertion layer):
+ * TokenExchangePrincipal tep = getTokenExchangePrincipal(subject);
+ * if (tep != null) {
+ * // Set up impersonation: actor acts as subject
+ * mappedPrincipalName = tep.getSubjectPrincipalName();
+ * // This triggers existing impersonation logic
+ * }
+ * </pre>
+ *
+ * @see <a
href="https://datatracker.ietf.org/doc/html/rfc8693#section-2.1">RFC 8693
Section 2.1</a>
+ */
+public interface TokenExchangePrincipal extends Principal {
+
+ /**
+ * Get the subject principal name (the identity on behalf of whom the
request is made).
+ *
+ * <p>In the token exchange flow, this is extracted from the subject_token
parameter.
+ * This identity will typically become the {@link ImpersonatedPrincipal}
after the
+ * identity assertion layer processes the token exchange.</p>
+ *
+ * @return the subject principal name, never null
+ */
+ String getSubjectPrincipalName();
+
+ /**
+ * Get the issuer of the subject token.
+ *
+ * <p>Combined with the subject principal name, this provides a globally
unique
+ * identity for the subject. This is important for audit trails and security
+ * decisions where the issuer context matters.</p>
+ *
+ * @return the subject token issuer, may be null if not available
+ */
+ String getSubjectIssuer();
+
+ /**
+ * Get the actor principal name (the identity of the acting party).
+ *
+ * <p>In the token exchange flow, this is extracted from the actor_token
parameter.
+ * This identity represents the authenticated party who is authorized to act
on
+ * behalf of the subject. This will typically be the {@link
PrimaryPrincipal}.</p>
+ *
+ * @return the actor principal name, never null
+ */
+ String getActorPrincipalName();
+
+ /**
+ * Get the issuer of the actor token.
+ *
+ * <p>Combined with the actor principal name, this provides a globally unique
+ * identity for the actor. This is important for audit trails and security
+ * decisions where the issuer context matters.</p>
+ *
+ * @return the actor token issuer, may be null if not available
+ */
+ String getActorIssuer();
+
+ /**
+ * Returns the actor principal name.
+ *
+ * <p>This implements {@link Principal#getName()} and returns the actor's
identity
+ * since the actor is the authenticated party performing the token
exchange.</p>
+ *
+ * @return the actor principal name
+ */
+ @Override
+ default String getName() {
+ return getActorPrincipalName();
+ }
+}
diff --git
a/gateway-spi/src/main/java/org/apache/knox/gateway/security/TokenExchangePrincipalImpl.java
b/gateway-spi/src/main/java/org/apache/knox/gateway/security/TokenExchangePrincipalImpl.java
new file mode 100644
index 000000000..01cfb48f1
--- /dev/null
+++
b/gateway-spi/src/main/java/org/apache/knox/gateway/security/TokenExchangePrincipalImpl.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.security;
+
+import java.util.Objects;
+
+/**
+ * Implementation of TokenExchangePrincipal that holds RFC 8693 token exchange
metadata.
+ */
+public class TokenExchangePrincipalImpl implements TokenExchangePrincipal {
+ private final String subjectPrincipalName;
+ private final String subjectIssuer;
+ private final String actorPrincipalName;
+ private final String actorIssuer;
+
+ /**
+ * Creates a new TokenExchangePrincipal with the specified subject and actor
identities.
+ *
+ * @param subjectPrincipalName the subject principal name (required)
+ * @param subjectIssuer the subject token issuer (may be null)
+ * @param actorPrincipalName the actor principal name (required)
+ * @param actorIssuer the actor token issuer (may be null)
+ * @throws IllegalArgumentException if subjectPrincipalName or
actorPrincipalName is null
+ */
+ public TokenExchangePrincipalImpl(String subjectPrincipalName, String
subjectIssuer,
+ String actorPrincipalName, String
actorIssuer) {
+ if (subjectPrincipalName == null || subjectPrincipalName.isEmpty()) {
+ throw new IllegalArgumentException("Subject principal name cannot be
null or empty");
+ }
+ if (actorPrincipalName == null || actorPrincipalName.isEmpty()) {
+ throw new IllegalArgumentException("Actor principal name cannot be null
or empty");
+ }
+ this.subjectPrincipalName = subjectPrincipalName;
+ this.subjectIssuer = subjectIssuer;
+ this.actorPrincipalName = actorPrincipalName;
+ this.actorIssuer = actorIssuer;
+ }
+
+ @Override
+ public String getSubjectPrincipalName() {
+ return subjectPrincipalName;
+ }
+
+ @Override
+ public String getSubjectIssuer() {
+ return subjectIssuer;
+ }
+
+ @Override
+ public String getActorPrincipalName() {
+ return actorPrincipalName;
+ }
+
+ @Override
+ public String getActorIssuer() {
+ return actorIssuer;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("TokenExchangePrincipal[actor=");
+ sb.append(actorPrincipalName);
+ if (actorIssuer != null) {
+ sb.append("@").append(actorIssuer);
+ }
+ sb.append(", subject=").append(subjectPrincipalName);
+ if (subjectIssuer != null) {
+ sb.append("@").append(subjectIssuer);
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof TokenExchangePrincipal)) {
+ return false;
+ }
+ TokenExchangePrincipal that = (TokenExchangePrincipal) o;
+ return Objects.equals(subjectPrincipalName, that.getSubjectPrincipalName())
+ && Objects.equals(subjectIssuer, that.getSubjectIssuer())
+ && Objects.equals(actorPrincipalName, that.getActorPrincipalName())
+ && Objects.equals(actorIssuer, that.getActorIssuer());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(subjectPrincipalName, subjectIssuer,
actorPrincipalName, actorIssuer);
+ }
+}