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
@@ -0,0 +1,70 @@
package org.keycloak.tests.broker.oidc;

import org.keycloak.authentication.AuthenticationFlow;
import org.keycloak.authentication.authenticators.client.JWTClientAuthenticator;
import org.keycloak.crypto.Algorithm;
import org.keycloak.crypto.KeyUse;
import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.representations.idm.AuthenticationExecutionRepresentation;
import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.IdentityProviderRepresentation;
import org.keycloak.representations.idm.KeysMetadataRepresentation.KeyMetadataRepresentation;
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
import org.keycloak.testframework.realm.AuthenticationExecutionBuilder;
import org.keycloak.testframework.realm.AuthenticationFlowBuilder;
import org.keycloak.tests.broker.AbstractKcOidcBrokerTest;
import org.keycloak.tests.common.CustomProvidersServerConfig;
import org.keycloak.tests.providers.broker.oidc.ClientIdRequiredJWTClientAuthenticator;

import org.junit.jupiter.api.BeforeEach;

@KeycloakIntegrationTest(config = CustomProvidersServerConfig.class)
public class KcOidcBrokerPrivateKeyJwtClientIdRequiredTest extends AbstractKcOidcBrokerTest {

@BeforeEach
void configureClientIdRequiredJwt() {
AuthenticationFlowRepresentation clientFlow = AuthenticationFlowBuilder.create()
.alias("new-client-flow")
.description("Base authentication for clients")
.providerId(AuthenticationFlow.CLIENT_FLOW)
.topLevel(true)
.builtIn(false)
.build();
providerRealm.admin().flows().createFlow(clientFlow);

var realm = providerRealm.admin().toRepresentation();
realm.setClientAuthenticationFlow(clientFlow.getAlias());
providerRealm.admin().update(realm);

clientFlow = providerRealm.admin().flows().getFlows().stream()
.filter(f -> "new-client-flow".equals(f.getAlias()))
.findFirst().orElseThrow();

AuthenticationExecutionRepresentation execution = AuthenticationExecutionBuilder.create()
.parentFlow(clientFlow.getId())
.requirement(AuthenticationExecutionModel.Requirement.REQUIRED.toString())
.authenticator(ClientIdRequiredJWTClientAuthenticator.PROVIDER_ID)
.priority(10)
.authenticatorFlow(false)
.build();
providerRealm.admin().flows().addExecution(execution);

KeyMetadataRepresentation rsaKey = consumerRealm.admin().keys().getKeyMetadata().getKeys().stream()
.filter(k -> k.getPublicKey() != null && KeyUse.SIG.equals(k.getUse())
&& Algorithm.RS256.equals(k.getAlgorithm()))
.findFirst().orElseThrow();

ClientRepresentation client = providerRealm.admin().clients().findByClientId(CLIENT_ID).get(0);
client.setClientAuthenticatorType(ClientIdRequiredJWTClientAuthenticator.PROVIDER_ID);
client.getAttributes().put(JWTClientAuthenticator.CERTIFICATE_ATTR, rsaKey.getCertificate());
providerRealm.admin().clients().get(client.getId()).update(client);

IdentityProviderRepresentation idp = consumerRealm.admin()
.identityProviders().get(getIdpAlias()).toRepresentation();
idp.getConfig().put("clientSecret", null);
idp.getConfig().put("clientAuthMethod", OIDCLoginProtocol.PRIVATE_KEY_JWT);
consumerRealm.admin().identityProviders().get(getIdpAlias()).update(idp);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package org.keycloak.tests.broker.oidc;

import org.keycloak.authentication.authenticators.client.JWTClientAuthenticator;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.keys.KeyProvider;
import org.keycloak.models.utils.DefaultKeyProviders;
import org.keycloak.protocol.oidc.OIDCConfigAttributes;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.ComponentRepresentation;
import org.keycloak.representations.idm.IdentityProviderRepresentation;
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
import org.keycloak.tests.broker.AbstractKcOidcBrokerTest;
import org.keycloak.tests.common.CustomProvidersServerConfig;

import org.junit.jupiter.api.BeforeEach;

@KeycloakIntegrationTest(config = CustomProvidersServerConfig.class)
public class KcOidcBrokerPrivateKeyJwtMissingUseTest extends AbstractKcOidcBrokerTest {

@BeforeEach
void configurePrivateKeyJwtWithMissingUse() {
ComponentRepresentation ecdsaKey = new ComponentRepresentation();
ecdsaKey.setName("ecdsa-generated");
ecdsaKey.setProviderId("ecdsa-generated");
ecdsaKey.setProviderType(KeyProvider.class.getName());
MultivaluedHashMap<String, String> keyConfig = new MultivaluedHashMap<>();
keyConfig.putSingle("priority", DefaultKeyProviders.DEFAULT_PRIORITY);
keyConfig.putSingle("ecdsaEllipticCurveKey", "P-384");
ecdsaKey.setConfig(keyConfig);
consumerRealm.admin().components().add(ecdsaKey).close();

String consumerBaseUrl = consumerRealm.getBaseUrl();
ClientRepresentation client = providerRealm.admin().clients().findByClientId(CLIENT_ID).get(0);
client.setClientAuthenticatorType(JWTClientAuthenticator.PROVIDER_ID);
client.getAttributes().put(OIDCConfigAttributes.USE_JWKS_URL, "true");
client.getAttributes().put(OIDCConfigAttributes.JWKS_URL,
consumerBaseUrl + "/missing-use-jwks/jwks");
providerRealm.admin().clients().get(client.getId()).update(client);

IdentityProviderRepresentation idp = consumerRealm.admin()
.identityProviders().get(getIdpAlias()).toRepresentation();
idp.getConfig().put("clientSecret", null);
idp.getConfig().put("clientAuthMethod", OIDCLoginProtocol.PRIVATE_KEY_JWT);
idp.getConfig().put("clientAssertionSigningAlg", "ES384");
consumerRealm.admin().identityProviders().get(getIdpAlias()).update(idp);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package org.keycloak.tests.broker.oidc;

import org.keycloak.authentication.authenticators.client.JWTClientAuthenticator;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.keys.KeyProvider;
import org.keycloak.models.utils.DefaultKeyProviders;
import org.keycloak.protocol.oidc.OIDCConfigAttributes;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.ComponentRepresentation;
import org.keycloak.representations.idm.IdentityProviderRepresentation;
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
import org.keycloak.tests.broker.AbstractKcOidcBrokerTest;
import org.keycloak.tests.common.CustomProvidersServerConfig;

import org.junit.jupiter.api.BeforeEach;

@KeycloakIntegrationTest(config = CustomProvidersServerConfig.class)
public class KcOidcBrokerPrivateKeyJwtUnsupportedKeyTest extends AbstractKcOidcBrokerTest {

@BeforeEach
void configurePrivateKeyJwtWithUnsupportedKey() {
ComponentRepresentation ecdsaKey = new ComponentRepresentation();
ecdsaKey.setName("ecdsa-generated");
ecdsaKey.setProviderId("ecdsa-generated");
ecdsaKey.setProviderType(KeyProvider.class.getName());
MultivaluedHashMap<String, String> keyConfig = new MultivaluedHashMap<>();
keyConfig.putSingle("priority", DefaultKeyProviders.DEFAULT_PRIORITY);
keyConfig.putSingle("ecdsaEllipticCurveKey", "P-384");
ecdsaKey.setConfig(keyConfig);
consumerRealm.admin().components().add(ecdsaKey).close();

String consumerBaseUrl = consumerRealm.getBaseUrl();
ClientRepresentation client = providerRealm.admin().clients().findByClientId(CLIENT_ID).get(0);
client.setClientAuthenticatorType(JWTClientAuthenticator.PROVIDER_ID);
client.getAttributes().put(OIDCConfigAttributes.USE_JWKS_URL, "true");
client.getAttributes().put(OIDCConfigAttributes.JWKS_URL,
consumerBaseUrl + "/unsupported-key-jwks/jwks");
providerRealm.admin().clients().get(client.getId()).update(client);

IdentityProviderRepresentation idp = consumerRealm.admin()
.identityProviders().get(getIdpAlias()).toRepresentation();
idp.getConfig().put("clientSecret", null);
idp.getConfig().put("clientAuthMethod", OIDCLoginProtocol.PRIVATE_KEY_JWT);
idp.getConfig().put("clientAssertionSigningAlg", "ES384");
consumerRealm.admin().identityProviders().get(getIdpAlias()).update(idp);
}
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,4 @@
/*
* Copyright 2023 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.testsuite.broker.oidc;
package org.keycloak.tests.providers.broker.oidc;

import java.util.Collections;
import java.util.Set;
Expand Down Expand Up @@ -58,7 +41,6 @@ public String getId() {

@Override
public Set<String> getProtocolAuthenticatorMethods(String loginProtocol) {
// Do not add as it will affect the well known provider test
return Collections.emptySet();
}
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,4 @@
/*
* Copyright 2024 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.testsuite.broker.oidc;
package org.keycloak.tests.providers.broker.oidc;

import java.security.cert.X509Certificate;
import java.util.ArrayList;
Expand All @@ -37,15 +20,21 @@
import org.keycloak.jose.jwk.JWKBuilder;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.services.resource.RealmResourceProvider;

public class UnsupportedKeyJwksRestResource {
public class UnsupportedKeyJwksRealmResourceProvider implements RealmResourceProvider {

private final KeycloakSession session;

public UnsupportedKeyJwksRestResource(KeycloakSession session) {
public UnsupportedKeyJwksRealmResourceProvider(KeycloakSession session) {
this.session = session;
}

@Override
public Object getResource() {
return this;
}

@GET
@Path("jwks")
@Produces(MediaType.APPLICATION_JSON)
Expand All @@ -70,7 +59,6 @@ public Response jwks() {
.filter(Objects::nonNull)
.collect(Collectors.toCollection(ArrayList::new));

// Add unsupported jwk
JWK unsupported = new JWK();
unsupported.setKeyType("EC");
unsupported.setOtherClaims("crv", "unsupportedsecp256k1");
Expand All @@ -84,4 +72,8 @@ public Response jwks() {

return Response.ok(keySet).build();
}

@Override
public void close() {
}
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,4 @@
/*
* Copyright 2024 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.testsuite.broker.oidc;
package org.keycloak.tests.providers.broker.oidc;

import org.keycloak.Config.Scope;
import org.keycloak.models.KeycloakSession;
Expand Down Expand Up @@ -48,5 +31,4 @@ public void postInit(KeycloakSessionFactory factory) {
@Override
public void close() {
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.keycloak.tests.providers.broker.oidc.ClientIdRequiredJWTClientAuthenticator
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
org.keycloak.tests.providers.rest.ErrorTestingRealmResourceProviderFactory
org.keycloak.tests.providers.rest.CookieTestingRealmResourceProviderFactory
org.keycloak.tests.providers.broker.oidc.MissingUseJwksRealmResourceProviderFactory
org.keycloak.tests.providers.broker.oidc.UnsupportedKeyJwksRealmResourceProviderFactory

This file was deleted.

This file was deleted.

Loading
Loading