+
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.keycloak.broker.provider.BrokeredIdentityContext;
import org.keycloak.broker.provider.ExchangeExternalToken;
import org.keycloak.broker.provider.ExchangeTokenToIdentityProviderToken;
import org.keycloak.broker.provider.IdentityBrokerException;
import org.keycloak.broker.provider.IdentityProvider;
import org.keycloak.broker.provider.IdentityProviderMapper;
import org.keycloak.broker.provider.IdentityProviderMapperSyncModeDelegate;
Expand Down Expand Up @@ -82,8 +83,8 @@
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

import jakarta.ws.rs.core.HttpHeaders;
Expand Down Expand Up @@ -553,41 +554,20 @@ protected Response exchangeClientToSAML2Client(UserModel targetUser, UserSession
return cors.add(Response.ok(res, MediaType.APPLICATION_JSON_TYPE));
}

protected Response exchangeExternalToken(String issuer, String subjectToken) {
AtomicReference<ExchangeExternalToken> externalIdp = new AtomicReference<>(null);
AtomicReference<IdentityProviderModel> externalIdpModel = new AtomicReference<>(null);

protected Response exchangeExternalToken(String subjectIssuer, String subjectToken) {
// try to find the IDP whose alias matches the issuer or the subject issuer in the form params.
this.locateExchangeExternalTokenByAlias(issuer, externalIdp, externalIdpModel);
if (externalIdp.get() == null && formParams.getFirst(OAuth2Constants.SUBJECT_ISSUER) != null) {
this.locateExchangeExternalTokenByAlias(formParams.getFirst(OAuth2Constants.SUBJECT_ISSUER), externalIdp, externalIdpModel);
}

if (externalIdp.get() == null) { // searching by alias didn't work, search all IDPs using ExchangeExternalToken.isIssuer to find a match
session.identityProviders().getAllStream().filter(idpModel -> {
IdentityProvider idp = IdentityBrokerService.getIdentityProviderFactory(session, idpModel).create(session, idpModel);
if (idp instanceof ExchangeExternalToken) {
ExchangeExternalToken external = (ExchangeExternalToken) idp;
if (external.isIssuer(issuer, formParams)) {
externalIdp.set(external);
externalIdpModel.set(idpModel);
return true;
}
}
return false;
}).findFirst();
}
ExternalExchangeContext externalExchangeContext = this.locateExchangeExternalTokenByAlias(subjectIssuer);

if (externalIdp.get() == null) {
if (externalExchangeContext == null) {
event.error(Errors.INVALID_ISSUER);
throw new CorsErrorResponseException(cors, Errors.INVALID_ISSUER, "Invalid " + OAuth2Constants.SUBJECT_ISSUER + " parameter", Response.Status.BAD_REQUEST);
}
if (!AdminPermissions.management(session, realm).idps().canExchangeTo(client, externalIdpModel.get())) {
if (!AdminPermissions.management(session, realm).idps().canExchangeTo(client, externalExchangeContext.idpModel())) {
event.detail(Details.REASON, "client not allowed to exchange subject_issuer");
event.error(Errors.NOT_ALLOWED);
throw new CorsErrorResponseException(cors, OAuthErrorException.ACCESS_DENIED, "Client not allowed to exchange", Response.Status.FORBIDDEN);
}
BrokeredIdentityContext context = externalIdp.get().exchangeExternal(event, formParams);
BrokeredIdentityContext context = externalExchangeContext.provider().exchangeExternal(event, formParams);
if (context == null) {
event.error(Errors.INVALID_ISSUER);
throw new CorsErrorResponseException(cors, Errors.INVALID_ISSUER, "Invalid " + OAuth2Constants.SUBJECT_ISSUER + " parameter", Response.Status.BAD_REQUEST);
Expand All @@ -596,10 +576,10 @@ protected Response exchangeExternalToken(String issuer, String subjectToken) {
UserModel user = importUserFromExternalIdentity(context);

UserSessionModel userSession = new UserSessionManager(session).createUserSession(realm, user, user.getUsername(), clientConnection.getRemoteAddr(), "external-exchange", false, null, null);
externalIdp.get().exchangeExternalComplete(userSession, context, formParams);
externalExchangeContext.provider().exchangeExternalComplete(userSession, context, formParams);

// this must exist so that we can obtain access token from user session if idp's store tokens is off
userSession.setNote(IdentityProvider.EXTERNAL_IDENTITY_PROVIDER, externalIdpModel.get().getAlias());
userSession.setNote(IdentityProvider.EXTERNAL_IDENTITY_PROVIDER, externalExchangeContext.idpModel().getAlias());
userSession.setNote(IdentityProvider.FEDERATED_ACCESS_TOKEN, subjectToken);

context.addSessionNotesToUserSession(userSession);
Expand Down Expand Up @@ -734,15 +714,28 @@ private void updateUserSessionFromClientAuth(UserSessionModel userSession) {
}
}

private void locateExchangeExternalTokenByAlias(String alias, AtomicReference<ExchangeExternalToken> externalIdp,
AtomicReference<IdentityProviderModel> externalIdpModel) {
record ExternalExchangeContext (ExchangeExternalToken provider, IdentityProviderModel idpModel) {};

private ExternalExchangeContext locateExchangeExternalTokenByAlias(String alias) {
try {
IdentityProvider<?> idp = IdentityBrokerService.getIdentityProvider(session, alias);

IdentityProviderModel idpModel = session.identityProviders().getByAlias(alias);
IdentityProvider idp = IdentityBrokerService.getIdentityProviderFactory(session, idpModel).create(session, idpModel);
if (idp instanceof ExchangeExternalToken) {
externalIdp.set((ExchangeExternalToken) idp);
externalIdpModel.set(idpModel);
if (idp instanceof ExchangeExternalToken external) {
IdentityProviderModel model = session.identityProviders().getByAlias(alias);
return new ExternalExchangeContext(external, model);
}
} catch (IdentityBrokerException ignore) {
}

return session.identityProviders().getAllStream().map(idpModel -> {
IdentityProvider<?> idp = IdentityBrokerService.getIdentityProvider(session, idpModel.getAlias());

if (idp instanceof ExchangeExternalToken external && external.isIssuer(alias, formParams)) {
return new ExternalExchangeContext(external, idpModel);
}

return null;
}).filter(Objects::nonNull).findFirst().orElse(null);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -1550,7 +1550,7 @@ private Stream<OIDCIdentityProvider> getOIDCIdentityProviders(LogoutToken logout
OIDCIdentityProviderConfig.ISSUER, logoutToken.getIssuer()
), -1, -1)
.map(model -> {
var idp = IdentityBrokerService.getIdentityProviderFactory(session, model).create(session, model);
var idp = IdentityBrokerService.getIdentityProvider(session, model.getAlias());

if (idp instanceof OIDCIdentityProvider oidcIdp) {
return oidcIdp;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -392,10 +392,7 @@ public Response performLogin(@PathParam("provider_alias") String providerAlias,
clientSessionCode.getClientSession().setClientNote(OIDCLoginProtocol.LOGIN_HINT_PARAM, loginHint);
}

IdentityProviderFactory<?> providerFactory = getIdentityProviderFactory(session, identityProviderModel);

IdentityProvider<?> identityProvider = providerFactory.create(session, identityProviderModel);

IdentityProvider<?> identityProvider = getIdentityProvider(session, identityProviderModel.getAlias());
Response response = identityProvider.performLogin(createAuthenticationRequest(identityProvider, providerAlias, clientSessionCode));

if (response != null) {
Expand Down Expand Up @@ -1330,7 +1327,11 @@ public static IdentityProvider<?> getIdentityProvider(KeycloakSession session, S
throw new IdentityBrokerException("Identity Provider [" + alias + "] not found.");
}

public static IdentityProviderFactory<?> getIdentityProviderFactory(KeycloakSession session, IdentityProviderModel model) {
private static IdentityProviderFactory<?> getIdentityProviderFactory(KeycloakSession session, IdentityProviderModel model) {
if (model == null) {
return null;
}

return Stream.concat(session.getKeycloakSessionFactory().getProviderFactoriesStream(IdentityProvider.class),
session.getKeycloakSessionFactory().getProviderFactoriesStream(SocialIdentityProvider.class))
.filter(providerFactory -> Objects.equals(providerFactory.getId(), model.getProviderId()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -493,8 +493,7 @@ public ManagementPermissionReference setManagementPermissionsEnabled(ManagementP
@Operation(summary = "Reaload keys for the identity provider if the provider supports it, \"true\" is returned if reload was performed, \"false\" if not.")
public boolean reloadKeys() {
this.auth.realm().requireManageIdentityProviders();
IdentityProviderFactory<?> providerFactory = IdentityBrokerService.getIdentityProviderFactory(session, identityProviderModel);
IdentityProvider provider = providerFactory.create(session, identityProviderModel);
IdentityProvider<?> provider = IdentityBrokerService.getIdentityProvider(session, identityProviderModel.getAlias());
return provider.reloadKeys();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ protected void applyDefaultConfiguration(final Map<String, String> config, Ident
config.put("clientId", CLIENT_ID);
config.put("clientSecret", CLIENT_SECRET);
config.put("prompt", "login");
config.put(OIDCIdentityProviderConfig.ISSUER, getProviderRoot() + "/auth/realms/" + REALM_PROV_NAME);
config.put("authorizationUrl", getProviderRoot() + "/auth/realms/" + REALM_PROV_NAME + "/protocol/openid-connect/auth");
config.put("tokenUrl", getProviderRoot() + "/auth/realms/" + REALM_PROV_NAME + "/protocol/openid-connect/token");
config.put("logoutUrl", getProviderRoot() + "/auth/realms/" + REALM_PROV_NAME + "/protocol/openid-connect/logout");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,17 @@ protected BrokerConfiguration getBrokerConfiguration() {

@Test
public void testExternalInternalTokenExchange() throws Exception {
assertExternalToInternalExchange(bc.getIDPAlias());
}

@Test
public void testExternalInternalTokenExchangeUsingIssuer() throws Exception {
RealmResource consumerRealm = realmsResouce().realm(bc.consumerRealmName());
IdentityProviderRepresentation broker = consumerRealm.identityProviders().get(bc.getIDPAlias()).toRepresentation();
assertExternalToInternalExchange(broker.getConfig().get(OIDCIdentityProviderConfigRep.ISSUER));
}

private void assertExternalToInternalExchange(String subjectIssuer) throws Exception {
RealmResource providerRealm = realmsResouce().realm(bc.providerRealmName());
ClientsResource clients = providerRealm.clients();
ClientRepresentation brokerApp = clients.findByClientId("brokerapp").get(0);
Expand Down Expand Up @@ -125,7 +136,7 @@ public void testExternalInternalTokenExchange() throws Exception {
.param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.TOKEN_EXCHANGE_GRANT_TYPE)
.param(OAuth2Constants.SUBJECT_TOKEN, tokenResponse.getIdToken())
.param(OAuth2Constants.SUBJECT_TOKEN_TYPE, OAuth2Constants.ID_TOKEN_TYPE)
.param(OAuth2Constants.SUBJECT_ISSUER, bc.getIDPAlias())
.param(OAuth2Constants.SUBJECT_ISSUER, subjectIssuer)
.param(OAuth2Constants.SCOPE, OAuth2Constants.SCOPE_OPENID)

))) {
Expand Down
Loading
点击 这是indexloc提供的php浏览器服务,不要输入任何密码和下载