keycloak-aplcache

Details

diff --git a/services/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java b/services/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java
index 2d8f756..042779f 100755
--- a/services/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java
+++ b/services/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java
@@ -281,16 +281,7 @@ public class SamlProtocol implements LoginProtocol {
             // "G-" stands for "generated" Add this for the slight possibility of collisions.
             return "G-" + UUID.randomUUID().toString();
         } else if (nameIdFormat.equals(JBossSAMLURIConstants.NAMEID_FORMAT_PERSISTENT.get())) {
-            // generate a persistent user id specifically for each client.
-            UserModel user = userSession.getUser();
-            String name = SAML_PERSISTENT_NAME_ID_FOR + "." + clientSession.getClient().getClientId();
-            String samlPersistentId = user.getFirstAttribute(name);
-            if (samlPersistentId != null)
-                return samlPersistentId;
-            // "G-" stands for "generated"
-            samlPersistentId = "G-" + UUID.randomUUID().toString();
-            user.setSingleAttribute(name, samlPersistentId);
-            return samlPersistentId;
+            return getPersistentNameId(clientSession, userSession);
         } else if (nameIdFormat.equals(JBossSAMLURIConstants.NAMEID_FORMAT_UNSPECIFIED.get())) {
             // TODO: Support for persistent NameID (pseudo-random identifier persisted in user object)
             return userSession.getUser().getUsername();
@@ -299,6 +290,43 @@ public class SamlProtocol implements LoginProtocol {
         }
     }
 
+    /**
+     * Attempts to retrieve the persistent type NameId as follows:
+     *
+     * <ol>
+     *     <li>saml.persistent.name.id.for.$clientId user attribute</li>
+     *     <li>saml.persistent.name.id.for.* user attribute</li>
+     *     <li>G-$randomUuid</li>
+     * </ol>
+     *
+     * If a randomUuid is generated, an attribute for the given saml.persistent.name.id.for.$clientId will be generated,
+     * otherwise no state change will occur with respect to the user's attributes.
+     *
+     * @return the user's persistent NameId
+     */
+    protected String getPersistentNameId(final ClientSessionModel clientSession, final UserSessionModel userSession) {
+        // attempt to retrieve the UserID for the client-specific attribute
+        final UserModel user = userSession.getUser();
+        final String clientNameId = String.format("%s.%s", SAML_PERSISTENT_NAME_ID_FOR,
+                clientSession.getClient().getClientId());
+        String samlPersistentNameId = user.getFirstAttribute(clientNameId);
+        if (samlPersistentNameId != null) {
+            return samlPersistentNameId;
+        }
+
+        // check for a wildcard attribute
+        final String wildcardNameId = String.format("%s.*", SAML_PERSISTENT_NAME_ID_FOR);
+        samlPersistentNameId = user.getFirstAttribute(wildcardNameId);
+        if (samlPersistentNameId != null) {
+            return samlPersistentNameId;
+        }
+
+        // default to generated.  "G-" stands for "generated"
+        samlPersistentNameId = "G-" + UUID.randomUUID().toString();
+        user.setSingleAttribute(clientNameId, samlPersistentNameId);
+        return samlPersistentNameId;
+    }
+
     @Override
     public Response authenticated(UserSessionModel userSession, ClientSessionCode accessCode) {
         ClientSessionModel clientSession = accessCode.getClientSession();