[OID4VCI] Fix order of protocol-type selection in admin-ui (#39564)

fixes #39563

Signed-off-by: Pascal Knüppel <pascal.knueppel@governikus.de>
This commit is contained in:
Pascal Knüppel 2025-06-05 10:08:35 +02:00 committed by GitHub
parent 41110823c7
commit 192c7bed57
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 92 additions and 0 deletions

View File

@ -36,6 +36,7 @@ import org.keycloak.protocol.oid4vc.issuance.OID4VCIssuerEndpoint;
import org.keycloak.protocol.oid4vc.issuance.mappers.OID4VCSubjectIdMapper;
import org.keycloak.protocol.oid4vc.issuance.mappers.OID4VCTargetRoleMapper;
import org.keycloak.protocol.oid4vc.issuance.mappers.OID4VCUserAttributeMapper;
import org.keycloak.protocol.oidc.OIDCLoginProtocolFactory;
import org.keycloak.representations.idm.ClientRepresentation;
/**
@ -123,4 +124,11 @@ public class OID4VCLoginProtocolFactory implements LoginProtocolFactory, OID4VCE
return PROTOCOL_ID;
}
/**
* defines the option-order in the admin-ui
*/
@Override
public int order() {
return OIDCLoginProtocolFactory.UI_ORDER - 20;
}
}

View File

@ -67,6 +67,11 @@ import static org.keycloak.models.ImpersonationSessionNote.IMPERSONATOR_USERNAME
public class OIDCLoginProtocolFactory extends AbstractLoginProtocolFactory {
private static final Logger logger = Logger.getLogger(OIDCLoginProtocolFactory.class);
/**
* determines the order in which the login protocols are displayed in the dropdown boxes in the UI
*/
public static final int UI_ORDER = 100;
public static final String USERNAME = "username";
public static final String EMAIL = "email";
public static final String EMAIL_VERIFIED = "email verified";
@ -542,4 +547,11 @@ public class OIDCLoginProtocolFactory extends AbstractLoginProtocolFactory {
}
}
/**
* defines the option-order in the admin-ui
*/
@Override
public int order() {
return UI_ORDER;
}
}

View File

@ -29,6 +29,7 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.protocol.AbstractLoginProtocolFactory;
import org.keycloak.protocol.LoginProtocol;
import org.keycloak.protocol.oidc.OIDCLoginProtocolFactory;
import org.keycloak.protocol.saml.mappers.AttributeStatementHelper;
import org.keycloak.organization.protocol.mappers.saml.OrganizationMembershipMapper;
import org.keycloak.protocol.saml.mappers.RoleListMapper;
@ -193,4 +194,11 @@ public class SamlProtocolFactory extends AbstractLoginProtocolFactory {
client.setArtifactBindingIdentifierFrom(clientRep.getClientId());
}
/**
* defines the option-order in the admin-ui
*/
@Override
public int order() {
return OIDCLoginProtocolFactory.UI_ORDER - 10;
}
}

View File

@ -0,0 +1,64 @@
/*
* Copyright 2025 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed 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.keycloak.protocol;
import org.junit.Assert;
import org.junit.Test;
import org.keycloak.protocol.oid4vc.OID4VCLoginProtocolFactory;
import org.keycloak.protocol.oidc.OIDCLoginProtocolFactory;
import org.keycloak.protocol.saml.SamlProtocolFactory;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.ServiceLoader;
/**
* @author Pascal Knüppel
*/
public class ProtocolFactoryTest {
/**
* this test makes sure that the LoginProtocolFactories represent the expected order in the UI for selection. The
* order-value is used to sort the protocol-selections in the drop-down boxes in the UI and openid-connect should be
* always set as default
*/
@Test
public void testOrderOfLoginProtocolFactories() {
Iterator<LoginProtocolFactory> iterator = ServiceLoader.load(LoginProtocolFactory.class).iterator();
Map<Integer, LoginProtocolFactory> factories = new LinkedHashMap<>();
int numberOfImplementations = 0;
LoginProtocolFactory factory;
while (iterator.hasNext()) {
factory = iterator.next();
factories.put(factory.order(), factory);
numberOfImplementations++;
}
Assert.assertEquals("No two LoginProtocolFactories must have the same order number",
numberOfImplementations, factories.size());
Assert.assertEquals("The OIDCLoginProtocolFactory should always come first!",
OIDCLoginProtocolFactory.class,
factories.get(OIDCLoginProtocolFactory.UI_ORDER).getClass());
Assert.assertEquals(SamlProtocolFactory.class,
factories.get(OIDCLoginProtocolFactory.UI_ORDER - 10).getClass());
Assert.assertEquals(OID4VCLoginProtocolFactory.class,
factories.get(OIDCLoginProtocolFactory.UI_ORDER - 20).getClass());
}
}