diff --git a/common/src/main/java/org/keycloak/common/Profile.java b/common/src/main/java/org/keycloak/common/Profile.java index 8f2f7c2942..55035cdade 100755 --- a/common/src/main/java/org/keycloak/common/Profile.java +++ b/common/src/main/java/org/keycloak/common/Profile.java @@ -57,8 +57,6 @@ public class Profile { IMPERSONATION("Ability for admins to impersonate users", Type.DEFAULT), - OPENSHIFT_INTEGRATION("Extension to enable securing OpenShift", Type.PREVIEW), - SCRIPTS("Write custom authenticators using JavaScript", Type.PREVIEW), TOKEN_EXCHANGE("Token Exchange Service", Type.PREVIEW), diff --git a/common/src/test/java/org/keycloak/common/ProfileTest.java b/common/src/test/java/org/keycloak/common/ProfileTest.java index f2c14954f5..6125cb7a6e 100644 --- a/common/src/test/java/org/keycloak/common/ProfileTest.java +++ b/common/src/test/java/org/keycloak/common/ProfileTest.java @@ -79,7 +79,6 @@ public class ProfileTest { Profile.Feature.RECOVERY_CODES, Profile.Feature.SCRIPTS, Profile.Feature.TOKEN_EXCHANGE, - Profile.Feature.OPENSHIFT_INTEGRATION, Profile.Feature.MAP_STORAGE, Profile.Feature.DECLARATIVE_USER_PROFILE, Profile.Feature.CLIENT_SECRET_ROTATION, @@ -91,7 +90,7 @@ public class ProfileTest { disabledFeatures.add(Profile.Feature.KERBEROS); } assertEquals(profile.getDisabledFeatures(), disabledFeatures); - assertEquals(profile.getPreviewFeatures(), Profile.Feature.ADMIN_FINE_GRAINED_AUTHZ, Profile.Feature.RECOVERY_CODES, Profile.Feature.SCRIPTS, Profile.Feature.TOKEN_EXCHANGE, Profile.Feature.OPENSHIFT_INTEGRATION, Profile.Feature.DECLARATIVE_USER_PROFILE, Profile.Feature.CLIENT_SECRET_ROTATION, Profile.Feature.UPDATE_EMAIL); + assertEquals(profile.getPreviewFeatures(), Profile.Feature.ADMIN_FINE_GRAINED_AUTHZ, Profile.Feature.RECOVERY_CODES, Profile.Feature.SCRIPTS, Profile.Feature.TOKEN_EXCHANGE, Profile.Feature.DECLARATIVE_USER_PROFILE, Profile.Feature.CLIENT_SECRET_ROTATION, Profile.Feature.UPDATE_EMAIL); } @Test diff --git a/dependencies/server-all/pom.xml b/dependencies/server-all/pom.xml index b844724398..485aacbcfa 100755 --- a/dependencies/server-all/pom.xml +++ b/dependencies/server-all/pom.xml @@ -112,11 +112,6 @@ org.keycloak keycloak-authz-policy-common - - - com.openshift - openshift-restclient-java - diff --git a/docs/documentation/release_notes/topics/22_0_0.adoc b/docs/documentation/release_notes/topics/22_0_0.adoc index 5144276a9e..7e7473fe18 100644 --- a/docs/documentation/release_notes/topics/22_0_0.adoc +++ b/docs/documentation/release_notes/topics/22_0_0.adoc @@ -55,3 +55,9 @@ For example, let's assume we want to overwrite the https://github.com/keycloak/k Installations which use Keycloak's `--proxy` configuration setting with mode *passthrough* should review the documentation as the behavior of this mode has changed. See the migration guide for more details. + += Removed openshift-integration feature and related providers + +The `openshift-integration` preview feature was removed from Keycloak codebase into separate extension project. + +See the migration guide for more details. diff --git a/docs/documentation/upgrading/topics/keycloak/changes-22_0_0.adoc b/docs/documentation/upgrading/topics/keycloak/changes-22_0_0.adoc index c0d3bad0d5..740f4d2086 100644 --- a/docs/documentation/upgrading/topics/keycloak/changes-22_0_0.adoc +++ b/docs/documentation/upgrading/topics/keycloak/changes-22_0_0.adoc @@ -226,3 +226,20 @@ This change is already in our documentation and in our quickstart repository. Fo If you cannot migrate your applications to Jakarta, you can still use the "legacy" SAML JEE adapter and still be able to integrate with future releases of the server. However, consider upgrading your applications as soon as possible because we are no longer providing support to JEE. + += Changes for openshift-integration feature + +The preview feature `openshift-integration` was removed from Keycloak codebase and moved into separate extension. This includes +moving of related providers such as custom client storage provider and token review endpoint for Openshift integration. + +If you used this feature, you should not use the `openshift-integration` feature anymore when starting Keycloak server and instead you need to deploy +the JAR file from custom extension. You can check the https://github.com/keycloak-extensions/keycloak-openshift-ext/[Openshift extension] and the instructions +in it's README file for how to deploy the extension to your Keycloak server. + += Removing thirdparty dependencies + +The removal of openshift-integration allows us to remove few thirdparty dependencies from Keycloak distribution. This includes +`openshift-rest-client`, `okio-jvm`, `okhttp`, `commons-lang`, `commons-compress`, `jboss-dmr` and `kotlin-stdlib`. This means that if you use +any of these libraries as dependencies of your own providers deployed to Keycloak server, you may also need to copy those `jar` files +explicitly to the Keycloak distribution `providers` directory as well. + diff --git a/federation/sssd/pom.xml b/federation/sssd/pom.xml index aa5f1a1f50..3897e63890 100644 --- a/federation/sssd/pom.xml +++ b/federation/sssd/pom.xml @@ -84,6 +84,11 @@ jboss-logging provided + + org.slf4j + slf4j-api + provided + diff --git a/misc/keycloak-test-helper/src/main/java/org/keycloak/test/builders/UserBuilder.java b/misc/keycloak-test-helper/src/main/java/org/keycloak/test/builders/UserBuilder.java new file mode 100644 index 0000000000..e5bdd36e9c --- /dev/null +++ b/misc/keycloak-test-helper/src/main/java/org/keycloak/test/builders/UserBuilder.java @@ -0,0 +1,206 @@ +/* + * 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.test.builders; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; + +import org.keycloak.models.credential.OTPCredentialModel; +import org.keycloak.models.utils.HmacOTP; +import org.keycloak.models.utils.ModelToRepresentation; +import org.keycloak.representations.idm.CredentialRepresentation; +import org.keycloak.representations.idm.FederatedIdentityRepresentation; +import org.keycloak.representations.idm.UserRepresentation; + +/** + * @author Stian Thorgersen + */ +public class UserBuilder { + + private final UserRepresentation rep; + + public static UserBuilder create() { + UserRepresentation rep = new UserRepresentation(); + rep.setEnabled(Boolean.TRUE); + return new UserBuilder(rep); + } + + public static UserBuilder edit(UserRepresentation rep) { + return new UserBuilder(rep); + } + + private UserBuilder(UserRepresentation rep) { + this.rep = rep; + } + + public UserBuilder id(String id) { + rep.setId(id); + return this; + } + + public UserBuilder username(String username) { + rep.setUsername(username); + return this; + } + + public UserBuilder firstName(String firstName) { + rep.setFirstName(firstName); + return this; + } + + public UserBuilder lastName(String lastName) { + rep.setLastName(lastName); + return this; + } + + /** + * This method adds additional passwords to the user. + */ + public UserBuilder addPassword(String password) { + if (rep.getCredentials() == null) { + rep.setCredentials(new LinkedList<>()); + } + + CredentialRepresentation credential = new CredentialRepresentation(); + credential.setType(CredentialRepresentation.PASSWORD); + credential.setValue(password); + + rep.getCredentials().add(credential); + return this; + } + + public UserBuilder addAttribute(String name, String... values) { + if (rep.getAttributes() == null) { + rep.setAttributes(new HashMap<>()); + } + + rep.getAttributes().put(name, Arrays.asList(values)); + return this; + } + + /** + * This method makes sure that there is one single password for the user. + */ + public UserBuilder password(String password) { + rep.setCredentials(null); + return addPassword(password); + } + + public UserBuilder email(String email) { + rep.setEmail(email); + return this; + } + + public UserBuilder emailVerified(boolean emailVerified) { + rep.setEmailVerified(emailVerified); + return this; + } + + public UserBuilder enabled(boolean enabled) { + rep.setEnabled(enabled); + return this; + } + + public UserBuilder addRoles(String... roles) { + if (rep.getRealmRoles() == null) { + rep.setRealmRoles(new ArrayList<>()); + } + rep.getRealmRoles().addAll(Arrays.asList(roles)); + return this; + } + + public UserBuilder role(String client, String role) { + if (rep.getClientRoles() == null) { + rep.setClientRoles(new HashMap<>()); + } + if (rep.getClientRoles().get(client) == null) { + rep.getClientRoles().put(client, new LinkedList<>()); + } + rep.getClientRoles().get(client).add(role); + return this; + } + + public UserBuilder requiredAction(String requiredAction) { + if (rep.getRequiredActions() == null) { + rep.setRequiredActions(new LinkedList<>()); + } + rep.getRequiredActions().add(requiredAction); + return this; + } + + public UserBuilder serviceAccountId(String serviceAccountId) { + rep.setServiceAccountClientId(serviceAccountId); + return this; + } + + public UserBuilder secret(CredentialRepresentation credential) { + if (rep.getCredentials() == null) { + rep.setCredentials(new LinkedList<>()); + } + + rep.getCredentials().add(credential); + rep.setTotp(true); + return this; + } + + public UserBuilder totpSecret(String totpSecret) { + CredentialRepresentation credential = ModelToRepresentation.toRepresentation( + OTPCredentialModel.createTOTP(totpSecret, 6, 30, HmacOTP.HMAC_SHA1)); + return secret(credential); + } + + public UserBuilder hotpSecret(String hotpSecret) { + CredentialRepresentation credential = ModelToRepresentation.toRepresentation( + OTPCredentialModel.createHOTP(hotpSecret, 6, 0, HmacOTP.HMAC_SHA1)); + return secret(credential); + } + + public UserBuilder otpEnabled() { + rep.setTotp(Boolean.TRUE); + return this; + } + + public UserBuilder addGroups(String... group) { + if (rep.getGroups() == null) { + rep.setGroups(new ArrayList<>()); + } + rep.getGroups().addAll(Arrays.asList(group)); + return this; + } + + public UserBuilder federatedLink(String identityProvider, String federatedUserId) { + if (rep.getFederatedIdentities() == null) { + rep.setFederatedIdentities(new LinkedList<>()); + } + FederatedIdentityRepresentation federatedIdentity = new FederatedIdentityRepresentation(); + federatedIdentity.setUserId(federatedUserId); + federatedIdentity.setUserName(rep.getUsername()); + federatedIdentity.setIdentityProvider(identityProvider); + + rep.getFederatedIdentities().add(federatedIdentity); + return this; + } + + public UserRepresentation build() { + return rep; + } +} \ No newline at end of file diff --git a/model/legacy-services/pom.xml b/model/legacy-services/pom.xml index 2bb276f09b..b6332e1f13 100644 --- a/model/legacy-services/pom.xml +++ b/model/legacy-services/pom.xml @@ -43,10 +43,6 @@ hamcrest test - - com.openshift - openshift-restclient-java - org.jboss.resteasy resteasy-core diff --git a/model/legacy-services/src/main/java/org/keycloak/storage/openshift/OpenshiftClientStorageProvider.java b/model/legacy-services/src/main/java/org/keycloak/storage/openshift/OpenshiftClientStorageProvider.java deleted file mode 100644 index b1d406eca9..0000000000 --- a/model/legacy-services/src/main/java/org/keycloak/storage/openshift/OpenshiftClientStorageProvider.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2018 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.storage.openshift; - -import com.openshift.restclient.IClient; -import com.openshift.restclient.NotFoundException; -import com.openshift.restclient.model.IResource; -import java.util.Collections; -import java.util.Map; -import org.keycloak.models.ClientModel; -import org.keycloak.models.ClientScopeModel; -import org.keycloak.models.KeycloakSession; -import org.keycloak.models.RealmModel; -import org.keycloak.storage.StorageId; -import org.keycloak.storage.client.ClientStorageProvider; -import org.keycloak.storage.client.ClientStorageProviderModel; - -import java.util.Map; -import java.util.regex.Matcher; -import java.util.stream.Stream; - -/** - * @author Pedro Igor - */ -public class OpenshiftClientStorageProvider implements ClientStorageProvider { - - private final KeycloakSession session; - private final ClientStorageProviderModel providerModel; - private final IClient client; - - OpenshiftClientStorageProvider(KeycloakSession session, ClientStorageProviderModel providerModel, IClient client) { - this.session = session; - this.providerModel = providerModel; - this.client = client; - } - - @Override - public ClientModel getClientById(RealmModel realm, String id) { - StorageId storageId = new StorageId(id); - if (!storageId.getProviderId().equals(providerModel.getId())) return null; - String clientId = storageId.getExternalId(); - return getClientByClientId(realm, clientId); - } - - @Override - public ClientModel getClientByClientId(RealmModel realm, String clientId) { - Matcher matcher = OpenshiftClientStorageProviderFactory.SERVICE_ACCOUNT_PATTERN.matcher(clientId); - IResource resource = null; - - if (matcher.matches()) { - resource = getServiceAccount(matcher.group(2), matcher.group(1)); - } else { - String defaultNamespace = providerModel.get(OpenshiftClientStorageProviderFactory.CONFIG_PROPERTY_DEFAULT_NAMESPACE); - - if (defaultNamespace != null) { - resource = getServiceAccount(clientId, defaultNamespace); - } - } - - if (resource == null) { - return null; - } - - return new OpenshiftSAClientAdapter(clientId, resource, client, session, realm, providerModel); - } - - @Override - public Stream searchClientsByClientIdStream(RealmModel realm, String clientId, Integer firstResult, Integer maxResults) { - // TODO not sure about this, but I don't see this implementation using the search now - return Stream.of(getClientByClientId(realm, clientId)); - } - - @Override - public Stream searchClientsByAttributes(RealmModel realm, Map attributes, Integer firstResult, Integer maxResults) { - // TODO not sure if we support searching clients for this provider - return Stream.empty(); - } - - @Override - public void close() { - - } - - private IResource getServiceAccount(String name, String namespace) { - try { - return client.get("ServiceAccount", name, namespace); - } catch (NotFoundException nfe) { - return null; - } - } - - @Override - public Map getClientScopes(RealmModel realm, ClientModel client, boolean defaultScopes) { - // TODO not sure about this, this implementation doesn't use it now - return Collections.EMPTY_MAP; - } -} diff --git a/model/legacy-services/src/main/java/org/keycloak/storage/openshift/OpenshiftClientStorageProviderFactory.java b/model/legacy-services/src/main/java/org/keycloak/storage/openshift/OpenshiftClientStorageProviderFactory.java deleted file mode 100644 index 59e05884ac..0000000000 --- a/model/legacy-services/src/main/java/org/keycloak/storage/openshift/OpenshiftClientStorageProviderFactory.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2018 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.storage.openshift; - -import static org.keycloak.storage.CacheableStorageProviderModel.CACHE_POLICY; - -import java.util.List; -import java.util.regex.Pattern; - -import com.openshift.restclient.ClientBuilder; -import com.openshift.restclient.IClient; -import org.keycloak.common.Profile; -import org.keycloak.component.ComponentModel; -import org.keycloak.component.ComponentValidationException; -import org.keycloak.models.KeycloakSession; -import org.keycloak.models.RealmModel; -import org.keycloak.provider.EnvironmentDependentProviderFactory; -import org.keycloak.provider.ProviderConfigProperty; -import org.keycloak.provider.ProviderConfigurationBuilder; -import org.keycloak.storage.CacheableStorageProviderModel; -import org.keycloak.storage.client.ClientStorageProviderFactory; -import org.keycloak.storage.client.ClientStorageProviderModel; - -/** - * @author Pedro Igor - */ -public class OpenshiftClientStorageProviderFactory implements ClientStorageProviderFactory, EnvironmentDependentProviderFactory { - - public static final String PROVIDER_ID = "openshift-oauth-client"; - static final Pattern SERVICE_ACCOUNT_PATTERN = Pattern.compile("system:serviceaccount:([^:]+):([^:]+)"); - public static final String CONFIG_PROPERTY_ACCESS_TOKEN = "openshift.access_token"; - public static final String CONFIG_PROPERTY_OPENSHIFT_URI = "openshift.uri"; - public static final String CONFIG_PROPERTY_DEFAULT_NAMESPACE = "openshift.namespace.default"; - public static final String CONFIG_PROPERTY_REQUIRE_USER_CONSENT = "user.consent.require"; - public static final String CONFIG_PROPERTY_DISPLAY_SCOPE_CONSENT_TEXT= "user.consent.scope.consent.text"; - - private final List CONFIG_PROPERTIES; - private IClient client; - - public OpenshiftClientStorageProviderFactory() { - CONFIG_PROPERTIES = ProviderConfigurationBuilder.create() - .property().name(CONFIG_PROPERTY_ACCESS_TOKEN) - .type(ProviderConfigProperty.STRING_TYPE) - .label("Access Token") - .helpText("Bearer token that will be used to invoke on Openshift api server. Must have privilege to lookup oauth clients, service accounts, and invoke on token review interface") - .add() - .property().name(CONFIG_PROPERTY_OPENSHIFT_URI) - .type(ProviderConfigProperty.STRING_TYPE) - .label("Openshift URL") - .helpText("Openshift api server URL base endpoint.") - .add() - .property().name(CONFIG_PROPERTY_DEFAULT_NAMESPACE) - .type(ProviderConfigProperty.STRING_TYPE) - .label("Default Namespace") - .helpText("The default namespace to use when the server is not able to resolve the namespace from the client identifier. Useful when clients in Openshift don't have names with the following pattern: " + SERVICE_ACCOUNT_PATTERN.pattern()) - .add() - .property().name(CONFIG_PROPERTY_REQUIRE_USER_CONSENT) - .type(ProviderConfigProperty.BOOLEAN_TYPE) - .defaultValue("true") - .label("Require User Consent") - .helpText("If set to true, clients from this storage will ask the end-user for any scope requested during the authorization flow") - .add() - .property().name(CONFIG_PROPERTY_DISPLAY_SCOPE_CONSENT_TEXT) - .type(ProviderConfigProperty.BOOLEAN_TYPE) - .defaultValue("true") - .label("Display Scopes Consent Text") - .helpText("If set to true, the consent page will display texts from the message bundle for scopes. Otherwise, the scope name will be displayed.") - .add() - .build(); - } - - @Override - public String getId() { - return PROVIDER_ID; - } - - @Override - public OpenshiftClientStorageProvider create(KeycloakSession session, ComponentModel model) { - ClientStorageProviderModel providerModel = createProviderModel(model); - IClient client = getClient(providerModel); - - if (client != null) { - return new OpenshiftClientStorageProvider(session, providerModel, client); - } - - client.getAuthorizationContext().setToken(providerModel.get(OpenshiftClientStorageProviderFactory.CONFIG_PROPERTY_ACCESS_TOKEN)); - - return new OpenshiftClientStorageProvider(session, providerModel, client); - } - - @Override - public String getHelpText() { - return "Openshift OAuth Client Adapter"; - } - - @Override - public List getConfigProperties() { - return CONFIG_PROPERTIES; - } - - @Override - public void validateConfiguration(KeycloakSession session, RealmModel realm, ComponentModel config) throws ComponentValidationException { - config.getConfig().putSingle(CACHE_POLICY, CacheableStorageProviderModel.CachePolicy.NO_CACHE.name()); - } - - @Override - public void onUpdate(KeycloakSession session, RealmModel realm, ComponentModel oldModel, ComponentModel newModel) { - if (!oldModel.get(CONFIG_PROPERTY_OPENSHIFT_URI).equals(newModel.get(CONFIG_PROPERTY_OPENSHIFT_URI))) { - client = null; - } else { - getClient(createProviderModel(newModel)).getAuthorizationContext().setToken(newModel.get(OpenshiftClientStorageProviderFactory.CONFIG_PROPERTY_ACCESS_TOKEN)); - } - } - - @Override - public boolean isSupported() { - return Profile.isFeatureEnabled(Profile.Feature.OPENSHIFT_INTEGRATION); - } - - private IClient getClient(ClientStorageProviderModel providerModel) { - synchronized (this) { - if (client == null) { - client = new ClientBuilder(providerModel.get(OpenshiftClientStorageProviderFactory.CONFIG_PROPERTY_OPENSHIFT_URI)).build(); - } - } - - return client; - } - - private ClientStorageProviderModel createProviderModel(ComponentModel model) { - return new ClientStorageProviderModel(model); - } -} diff --git a/model/legacy-services/src/main/java/org/keycloak/storage/openshift/OpenshiftSAClientAdapter.java b/model/legacy-services/src/main/java/org/keycloak/storage/openshift/OpenshiftSAClientAdapter.java deleted file mode 100755 index 9aaafb45b5..0000000000 --- a/model/legacy-services/src/main/java/org/keycloak/storage/openshift/OpenshiftSAClientAdapter.java +++ /dev/null @@ -1,483 +0,0 @@ -/* - * Copyright 2018 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.storage.openshift; - -import java.io.IOException; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.function.Consumer; -import java.util.function.Supplier; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import com.openshift.restclient.IClient; -import com.openshift.restclient.model.IResource; -import com.openshift.restclient.model.route.IRoute; -import org.keycloak.models.ClientModel; -import org.keycloak.models.ClientScopeModel; -import org.keycloak.models.KeycloakSession; -import org.keycloak.models.ProtocolMapperModel; -import org.keycloak.models.RealmModel; -import org.keycloak.models.RoleModel; -import org.keycloak.models.utils.KeycloakModelUtils; -import org.keycloak.models.utils.ModelToRepresentation; -import org.keycloak.models.utils.RepresentationToModel; -import org.keycloak.protocol.oidc.OIDCLoginProtocol; -import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper; -import org.keycloak.protocol.oidc.mappers.UserPropertyMapper; -import org.keycloak.representations.idm.ClientRepresentation; -import org.keycloak.representations.idm.ProtocolMapperRepresentation; -import org.keycloak.storage.client.AbstractReadOnlyClientScopeAdapter; -import org.keycloak.storage.client.AbstractReadOnlyClientStorageAdapter; -import org.keycloak.storage.client.ClientStorageProviderModel; -import org.keycloak.util.JsonSerialization; - -/** - * @author Pedro Igor - */ -public final class OpenshiftSAClientAdapter extends AbstractReadOnlyClientStorageAdapter { - - private static final String ANNOTATION_OAUTH_REDIRECT_URI = "serviceaccounts.openshift.io/oauth-redirecturi"; - private static final String ANNOTATION_OAUTH_REDIRECT_REFERENCE = "serviceaccounts.openshift.io/oauth-redirectreference"; - private static final Pattern ROLE_SCOPE_PATTERN = Pattern.compile("role:([^:]+):([^:!]+)(:[!])?"); - private static final Set OPTIONAL_SCOPES = Stream.of("user:info", "user:check-access").collect(Collectors.toSet()); - - private static Set createDefaultProtocolMappers() { - Set mappers = new HashSet<>(); - - ProtocolMapperModel mapper = OIDCAttributeMapperHelper.createClaimMapper("username", "username", - "preferred_username", "string", true, true, UserPropertyMapper.PROVIDER_ID); - mapper.setId(KeycloakModelUtils.generateId()); - - mappers.add(mapper); - - return mappers; - } - - private final IResource resource; - private final String clientId; - private final IClient client; - private final ClientRepresentation defaultConfig = new ClientRepresentation(); - - public OpenshiftSAClientAdapter(String clientId, IResource resource, IClient client, KeycloakSession session, RealmModel realm, ClientStorageProviderModel component) { - super(session, realm, component); - this.resource = resource; - this.clientId = clientId; - this.client = client; - } - - @Override - public String getClientId() { - return clientId; - } - - @Override - public String getName() { - return resource.getName(); - } - - @Override - public String getDescription() { - return getConfigOrDefault(() -> defaultConfig.getDescription(), defaultConfig::setDescription, new StringBuilder().append(resource.getKind()).append(" ").append(resource.getName()).append(" from namespace ").append(resource.getNamespace().getName()).toString()); - } - - @Override - public boolean isEnabled() { - return getConfigOrDefault(() -> defaultConfig.isEnabled(), defaultConfig::setEnabled, true); - } - - @Override - public boolean isAlwaysDisplayInConsole() { - return getConfigOrDefault(() -> defaultConfig.isAlwaysDisplayInConsole(), defaultConfig::setAlwaysDisplayInConsole, false); - } - - @Override - public Set getWebOrigins() { - return new HashSet<>(getConfigOrDefault(() -> defaultConfig.getWebOrigins(), defaultConfig::setWebOrigins, Collections.emptyList())); - } - - @Override - public Set getRedirectUris() { - return new HashSet<>(getConfigOrDefault((Supplier>) () -> defaultConfig.getRedirectUris(), - uris -> defaultConfig.setRedirectUris(uris), - (Supplier>) () -> resource.getAnnotations().entrySet().stream() - .filter((entry) -> entry.getKey().startsWith(ANNOTATION_OAUTH_REDIRECT_URI) || entry.getKey().startsWith(ANNOTATION_OAUTH_REDIRECT_REFERENCE)) - .map(entry -> { - if (entry.getKey().startsWith(ANNOTATION_OAUTH_REDIRECT_URI)) { - return entry.getValue(); - } else { - Map values; - - try { - values = JsonSerialization.readValue(entry.getValue(), Map.class); - } catch (IOException e) { - throw new RuntimeException("Failed to parse annotation [" + ANNOTATION_OAUTH_REDIRECT_REFERENCE + "]", e); - } - - Map reference = (Map) values.get("reference"); - String kind = (String) reference.get("kind"); - - if (!"Route".equals(kind)) { - throw new IllegalArgumentException("Only route references are supported for " + ANNOTATION_OAUTH_REDIRECT_REFERENCE); - } - - String name = (String) reference.get("name"); - IRoute route = client.get(kind, name, resource.getNamespace().getName()); - - StringBuilder url = new StringBuilder(route.getURL()); - - if (url.charAt(url.length() - 1) != '/') { - url.append('/'); - } - - return url.append('*').toString(); - } - }).collect(Collectors.toList()))); - } - - @Override - public String getManagementUrl() { - return null; - } - - @Override - public String getRootUrl() { - return null; - } - - @Override - public String getBaseUrl() { - return null; - } - - @Override - public boolean isBearerOnly() { - return false; - } - - @Override - public int getNodeReRegistrationTimeout() { - return 0; - } - - @Override - public String getClientAuthenticatorType() { - return null; - } - - @Override - public boolean validateSecret(String secret) { - //TODO: do we want SAs as confidential clients and enable client credentials grant and resource owner grant ? - return false; - } - - @Override - public String getSecret() { - //TODO: check if validate secret is enough, don't see a reason to return SAs secret - return null; - } - - @Override - public String getRegistrationToken() { - return null; - } - - @Override - public String getProtocol() { - //TODO: set login protocol, always oidc - return OIDCLoginProtocol.LOGIN_PROTOCOL; - } - - @Override - public String getAttribute(String name) { - return null; - } - - @Override - public Map getAttributes() { - return Collections.emptyMap(); - } - - @Override - public String getAuthenticationFlowBindingOverride(String binding) { - return null; - } - - @Override - public Map getAuthenticationFlowBindingOverrides() { - return Collections.emptyMap(); - } - - @Override - public boolean isFrontchannelLogout() { - return false; - } - - @Override - public boolean isFullScopeAllowed() { - return false; - } - - @Override - public boolean isPublicClient() { - return true; - } - - @Override - public boolean isConsentRequired() { - return component.get(OpenshiftClientStorageProviderFactory.CONFIG_PROPERTY_REQUIRE_USER_CONSENT, true); - } - - @Override - public boolean isDisplayOnConsentScreen() { - return false; - } - - @Override - public boolean isStandardFlowEnabled() { - return true; - } - - @Override - public boolean isImplicitFlowEnabled() { - return false; - } - - @Override - public boolean isDirectAccessGrantsEnabled() { - return false; - } - - @Override - public boolean isServiceAccountsEnabled() { - return false; - } - - @Override - public Map getClientScopes(boolean defaultScope) { - if (defaultScope) { - return Collections.emptyMap(); - } - - Map scopes = new HashMap<>(); - - for (String scope : OPTIONAL_SCOPES) { - scopes.put(scope, createClientScope(scope)); - } - - return scopes; - } - - @Override - public ClientScopeModel getDynamicClientScope(String scope) { - if (OPTIONAL_SCOPES.contains(scope)) { - return createClientScope(scope); - } - - Matcher matcher = ROLE_SCOPE_PATTERN.matcher(scope); - - if (matcher.matches()) { - String namespace = matcher.group(2); - - if (resource.getNamespace().getName().equals(namespace)) { - return createClientScope(scope); - } - } - - return null; - } - - @Override - public int getNotBefore() { - return 0; - } - - @Override - public Stream getProtocolMappersStream() { - List mappers = defaultConfig.getProtocolMappers(); - - if (mappers == null) { - Set defaultProtocolMappers = createDefaultProtocolMappers(); - defaultConfig.setProtocolMappers(defaultProtocolMappers.stream() - .map(ModelToRepresentation::toRepresentation).collect(Collectors.toList())); - return defaultProtocolMappers.stream(); - } - - return mappers.stream().map(RepresentationToModel::toModel); - } - - @Override - public ProtocolMapperModel getProtocolMapperById(String id) { - return getProtocolMappersStream() - .filter(protocolMapperModel -> Objects.equals(id, protocolMapperModel.getId())) - .findAny() - .orElse(null); - } - - @Override - public ProtocolMapperModel getProtocolMapperByName(String protocol, String name) { - return getProtocolMappersStream() - .filter(protocolMapperModel -> Objects.equals(name, protocolMapperModel.getName())) - .findAny() - .orElse(null); - } - - @Override - public Stream getScopeMappingsStream() { - return Stream.empty(); - } - - @Override - public Stream getRealmScopeMappingsStream() { - return Stream.empty(); - } - - @Override - public boolean hasScope(RoleModel role) { - return false; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !(o instanceof ClientModel)) return false; - - ClientModel that = (ClientModel) o; - return that.getId().equals(getId()); - } - - private V getConfigOrDefault(Supplier valueSupplier, Consumer valueConsumer, Supplier defaultValue) { - V value = valueSupplier.get(); - - if (value != null) { - return value; - } - - value = defaultValue.get(); - - if (valueConsumer != null) { - valueConsumer.accept(value); - } - - return value; - } - - private V getConfigOrDefault(Supplier valueSupplier, Consumer valueConsumer, V defaultValue) { - return getConfigOrDefault(valueSupplier, valueConsumer, (Supplier) () -> defaultValue); - } - - private ClientScopeModel createClientScope(String scope) { - ClientScopeModel managedScope = realm.getClientScopesStream() - .filter(scopeModel -> Objects.equals(scopeModel.getName(), scope)) - .findAny() - .orElse(null); - - if (managedScope != null) { - return managedScope; - } - - Map attributes = new HashMap<>(); - - attributes.put(ClientScopeModel.DISPLAY_ON_CONSENT_SCREEN, Boolean.valueOf(isConsentRequired()).toString()); - - if (component.get(OpenshiftClientStorageProviderFactory.CONFIG_PROPERTY_DISPLAY_SCOPE_CONSENT_TEXT, Boolean.TRUE)) { - StringBuilder consentText = new StringBuilder("${openshift.scope."); - - if (scope.indexOf(':') != -1) { - consentText.append(scope.replaceFirst(":", "_")); - } - - attributes.put(ClientScopeModel.CONSENT_SCREEN_TEXT, consentText.append("}").toString()); - } else { - attributes.put(ClientScopeModel.CONSENT_SCREEN_TEXT, scope); - } - - return new AbstractReadOnlyClientScopeAdapter() { - @Override - public String getId() { - return scope; - } - - @Override - public String getName() { - return scope; - } - - @Override - public RealmModel getRealm() { - return realm; - } - - @Override - public String getDescription() { - return scope; - } - - @Override - public String getProtocol() { - return OIDCLoginProtocol.LOGIN_PROTOCOL; - } - - @Override - public String getAttribute(String name) { - return attributes.get(name); - } - - @Override - public Map getAttributes() { - return attributes; - } - - @Override - public Stream getProtocolMappersStream() { - return createDefaultProtocolMappers().stream(); - } - - @Override - public ProtocolMapperModel getProtocolMapperById(String id) { - return null; - } - - @Override - public ProtocolMapperModel getProtocolMapperByName(String protocol, String name) { - return null; - } - - @Override - public Stream getScopeMappingsStream() { - return Stream.empty(); - } - - @Override - public Stream getRealmScopeMappingsStream() { - return Stream.empty(); - } - - @Override - public boolean hasScope(RoleModel role) { - return false; - } - }; - } -} diff --git a/model/legacy-services/src/main/resources/META-INF/services/org.keycloak.storage.client.ClientStorageProviderFactory b/model/legacy-services/src/main/resources/META-INF/services/org.keycloak.storage.client.ClientStorageProviderFactory deleted file mode 100644 index 1ac631b9cb..0000000000 --- a/model/legacy-services/src/main/resources/META-INF/services/org.keycloak.storage.client.ClientStorageProviderFactory +++ /dev/null @@ -1,18 +0,0 @@ -# -# * Copyright 2018 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. -# - -org.keycloak.storage.openshift.OpenshiftClientStorageProviderFactory \ No newline at end of file diff --git a/model/legacy/pom.xml b/model/legacy/pom.xml index f116a1f3f6..4f1c02fc16 100644 --- a/model/legacy/pom.xml +++ b/model/legacy/pom.xml @@ -43,10 +43,6 @@ hamcrest test - - com.openshift - openshift-restclient-java - \ No newline at end of file diff --git a/pom.xml b/pom.xml index 46018b2e29..2481f565e5 100644 --- a/pom.xml +++ b/pom.xml @@ -138,12 +138,8 @@ 5.0.3.Final 30.1-jre 1.4.20 - 4.10.0 2.6 - - 9.0.5.Final - 2.6 3.12.0 @@ -323,16 +319,6 @@ snakeyaml-engine ${org.snakeyaml.snakeyaml-engine.version} - - com.squareup.okhttp3 - okhttp - ${okhttp.version} - - - com.squareup.okhttp3 - logging-interceptor - ${okhttp.version} - org.jboss jboss-dmr @@ -1589,13 +1575,6 @@ ${project.version} - - - com.openshift - openshift-restclient-java - ${version.com.openshift.openshift-restclient-java} - - org.keycloak keycloak-saml-as7-modules diff --git a/quarkus/runtime/pom.xml b/quarkus/runtime/pom.xml index 8b50f2b625..0ed87c7305 100644 --- a/quarkus/runtime/pom.xml +++ b/quarkus/runtime/pom.xml @@ -667,23 +667,6 @@ org.twitter4j twitter4j-core - - - - com.openshift - openshift-restclient-java - ${version.com.openshift.openshift-restclient-java} - - - log4j - log4j - - - org.slf4j - slf4j-reload4j - - - diff --git a/quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/FeaturesDistTest.java b/quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/FeaturesDistTest.java index b1a75c8471..a3ad92e56d 100644 --- a/quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/FeaturesDistTest.java +++ b/quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/FeaturesDistTest.java @@ -28,7 +28,7 @@ import static org.keycloak.quarkus.runtime.cli.command.AbstractStartCommand.OPTI @LegacyStore public class FeaturesDistTest { - private static final String PREVIEW_FEATURES_EXPECTED_LOG = "Preview features enabled: admin-fine-grained-authz, client-secret-rotation, declarative-user-profile, openshift-integration, recovery-codes, scripts, token-exchange, update-email"; + private static final String PREVIEW_FEATURES_EXPECTED_LOG = "Preview features enabled: admin-fine-grained-authz, client-secret-rotation, declarative-user-profile, recovery-codes, scripts, token-exchange, update-email"; @Test public void testEnableOnBuild(KeycloakDistribution dist) { diff --git a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testBuildHelp.unix.approved.txt b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testBuildHelp.unix.approved.txt index 4b3ce5d13b..ba77ac1604 100644 --- a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testBuildHelp.unix.approved.txt +++ b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testBuildHelp.unix.approved.txt @@ -47,17 +47,15 @@ Feature: account2, account3, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, docker, dynamic-scopes, fips, impersonation, - js-adapter, kerberos, map-storage, openshift-integration, par, preview, - recovery-codes, scripts, step-up-authentication, token-exchange, - update-email, web-authn. + js-adapter, kerberos, map-storage, par, preview, recovery-codes, scripts, + step-up-authentication, token-exchange, update-email, web-authn. --features-disabled Disables a set of one or more features. Possible values are: account-api, account2, account3, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, docker, dynamic-scopes, fips, impersonation, - js-adapter, kerberos, map-storage, openshift-integration, par, preview, - recovery-codes, scripts, step-up-authentication, token-exchange, - update-email, web-authn. + js-adapter, kerberos, map-storage, par, preview, recovery-codes, scripts, + step-up-authentication, token-exchange, update-email, web-authn. HTTP/TLS: diff --git a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testBuildHelp.windows.approved.txt b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testBuildHelp.windows.approved.txt index e894d76aff..6a3d9e0ef6 100644 --- a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testBuildHelp.windows.approved.txt +++ b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testBuildHelp.windows.approved.txt @@ -47,17 +47,15 @@ Feature: account2, account3, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, docker, dynamic-scopes, fips, impersonation, - js-adapter, kerberos, map-storage, openshift-integration, par, preview, - recovery-codes, scripts, step-up-authentication, token-exchange, - update-email, web-authn. + js-adapter, kerberos, map-storage, par, preview, recovery-codes, scripts, + step-up-authentication, token-exchange, update-email, web-authn. --features-disabled Disables a set of one or more features. Possible values are: account-api, account2, account3, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, docker, dynamic-scopes, fips, impersonation, - js-adapter, kerberos, map-storage, openshift-integration, par, preview, - recovery-codes, scripts, step-up-authentication, token-exchange, - update-email, web-authn. + js-adapter, kerberos, map-storage, par, preview, recovery-codes, scripts, + step-up-authentication, token-exchange, update-email, web-authn. HTTP/TLS: diff --git a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testExportHelp.unix.approved.txt b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testExportHelp.unix.approved.txt index f95b6aa837..e1c8667cd7 100644 --- a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testExportHelp.unix.approved.txt +++ b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testExportHelp.unix.approved.txt @@ -57,17 +57,15 @@ Feature: account2, account3, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, docker, dynamic-scopes, fips, impersonation, - js-adapter, kerberos, map-storage, openshift-integration, par, preview, - recovery-codes, scripts, step-up-authentication, token-exchange, - update-email, web-authn. + js-adapter, kerberos, map-storage, par, preview, recovery-codes, scripts, + step-up-authentication, token-exchange, update-email, web-authn. --features-disabled Disables a set of one or more features. Possible values are: account-api, account2, account3, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, docker, dynamic-scopes, fips, impersonation, - js-adapter, kerberos, map-storage, openshift-integration, par, preview, - recovery-codes, scripts, step-up-authentication, token-exchange, - update-email, web-authn. + js-adapter, kerberos, map-storage, par, preview, recovery-codes, scripts, + step-up-authentication, token-exchange, update-email, web-authn. Config: diff --git a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testExportHelpAll.unix.approved.txt b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testExportHelpAll.unix.approved.txt index 011d1a8368..336b0cf9e1 100644 --- a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testExportHelpAll.unix.approved.txt +++ b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testExportHelpAll.unix.approved.txt @@ -120,17 +120,15 @@ Feature: account2, account3, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, docker, dynamic-scopes, fips, impersonation, - js-adapter, kerberos, map-storage, openshift-integration, par, preview, - recovery-codes, scripts, step-up-authentication, token-exchange, - update-email, web-authn. + js-adapter, kerberos, map-storage, par, preview, recovery-codes, scripts, + step-up-authentication, token-exchange, update-email, web-authn. --features-disabled Disables a set of one or more features. Possible values are: account-api, account2, account3, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, docker, dynamic-scopes, fips, impersonation, - js-adapter, kerberos, map-storage, openshift-integration, par, preview, - recovery-codes, scripts, step-up-authentication, token-exchange, - update-email, web-authn. + js-adapter, kerberos, map-storage, par, preview, recovery-codes, scripts, + step-up-authentication, token-exchange, update-email, web-authn. Config: diff --git a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testImportHelp.unix.approved.txt b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testImportHelp.unix.approved.txt index 2d6df946b9..e6c0d494f9 100644 --- a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testImportHelp.unix.approved.txt +++ b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testImportHelp.unix.approved.txt @@ -57,17 +57,15 @@ Feature: account2, account3, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, docker, dynamic-scopes, fips, impersonation, - js-adapter, kerberos, map-storage, openshift-integration, par, preview, - recovery-codes, scripts, step-up-authentication, token-exchange, - update-email, web-authn. + js-adapter, kerberos, map-storage, par, preview, recovery-codes, scripts, + step-up-authentication, token-exchange, update-email, web-authn. --features-disabled Disables a set of one or more features. Possible values are: account-api, account2, account3, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, docker, dynamic-scopes, fips, impersonation, - js-adapter, kerberos, map-storage, openshift-integration, par, preview, - recovery-codes, scripts, step-up-authentication, token-exchange, - update-email, web-authn. + js-adapter, kerberos, map-storage, par, preview, recovery-codes, scripts, + step-up-authentication, token-exchange, update-email, web-authn. Config: diff --git a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testImportHelpAll.unix.approved.txt b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testImportHelpAll.unix.approved.txt index 19a0c4fe7a..8b8a952461 100644 --- a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testImportHelpAll.unix.approved.txt +++ b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testImportHelpAll.unix.approved.txt @@ -120,17 +120,15 @@ Feature: account2, account3, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, docker, dynamic-scopes, fips, impersonation, - js-adapter, kerberos, map-storage, openshift-integration, par, preview, - recovery-codes, scripts, step-up-authentication, token-exchange, - update-email, web-authn. + js-adapter, kerberos, map-storage, par, preview, recovery-codes, scripts, + step-up-authentication, token-exchange, update-email, web-authn. --features-disabled Disables a set of one or more features. Possible values are: account-api, account2, account3, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, docker, dynamic-scopes, fips, impersonation, - js-adapter, kerberos, map-storage, openshift-integration, par, preview, - recovery-codes, scripts, step-up-authentication, token-exchange, - update-email, web-authn. + js-adapter, kerberos, map-storage, par, preview, recovery-codes, scripts, + step-up-authentication, token-exchange, update-email, web-authn. Config: diff --git a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelp.unix.approved.txt b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelp.unix.approved.txt index 41ccfa908f..12ee08fc36 100644 --- a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelp.unix.approved.txt +++ b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelp.unix.approved.txt @@ -72,17 +72,15 @@ Feature: account2, account3, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, docker, dynamic-scopes, fips, impersonation, - js-adapter, kerberos, map-storage, openshift-integration, par, preview, - recovery-codes, scripts, step-up-authentication, token-exchange, - update-email, web-authn. + js-adapter, kerberos, map-storage, par, preview, recovery-codes, scripts, + step-up-authentication, token-exchange, update-email, web-authn. --features-disabled Disables a set of one or more features. Possible values are: account-api, account2, account3, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, docker, dynamic-scopes, fips, impersonation, - js-adapter, kerberos, map-storage, openshift-integration, par, preview, - recovery-codes, scripts, step-up-authentication, token-exchange, - update-email, web-authn. + js-adapter, kerberos, map-storage, par, preview, recovery-codes, scripts, + step-up-authentication, token-exchange, update-email, web-authn. Hostname: diff --git a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelp.windows.approved.txt b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelp.windows.approved.txt index 6c9013180c..f046f28d61 100644 --- a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelp.windows.approved.txt +++ b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelp.windows.approved.txt @@ -72,17 +72,15 @@ Feature: account2, account3, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, docker, dynamic-scopes, fips, impersonation, - js-adapter, kerberos, map-storage, openshift-integration, par, preview, - recovery-codes, scripts, step-up-authentication, token-exchange, - update-email, web-authn. + js-adapter, kerberos, map-storage, par, preview, recovery-codes, scripts, + step-up-authentication, token-exchange, update-email, web-authn. --features-disabled Disables a set of one or more features. Possible values are: account-api, account2, account3, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, docker, dynamic-scopes, fips, impersonation, - js-adapter, kerberos, map-storage, openshift-integration, par, preview, - recovery-codes, scripts, step-up-authentication, token-exchange, - update-email, web-authn. + js-adapter, kerberos, map-storage, par, preview, recovery-codes, scripts, + step-up-authentication, token-exchange, update-email, web-authn. Hostname: diff --git a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelpAll.unix.approved.txt b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelpAll.unix.approved.txt index 1fd993e08c..5821c69d29 100644 --- a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelpAll.unix.approved.txt +++ b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelpAll.unix.approved.txt @@ -135,17 +135,15 @@ Feature: account2, account3, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, docker, dynamic-scopes, fips, impersonation, - js-adapter, kerberos, map-storage, openshift-integration, par, preview, - recovery-codes, scripts, step-up-authentication, token-exchange, - update-email, web-authn. + js-adapter, kerberos, map-storage, par, preview, recovery-codes, scripts, + step-up-authentication, token-exchange, update-email, web-authn. --features-disabled Disables a set of one or more features. Possible values are: account-api, account2, account3, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, docker, dynamic-scopes, fips, impersonation, - js-adapter, kerberos, map-storage, openshift-integration, par, preview, - recovery-codes, scripts, step-up-authentication, token-exchange, - update-email, web-authn. + js-adapter, kerberos, map-storage, par, preview, recovery-codes, scripts, + step-up-authentication, token-exchange, update-email, web-authn. Hostname: diff --git a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelpAll.windows.approved.txt b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelpAll.windows.approved.txt index 957efe00c9..802c7287b1 100644 --- a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelpAll.windows.approved.txt +++ b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelpAll.windows.approved.txt @@ -135,17 +135,15 @@ Feature: account2, account3, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, docker, dynamic-scopes, fips, impersonation, - js-adapter, kerberos, map-storage, openshift-integration, par, preview, - recovery-codes, scripts, step-up-authentication, token-exchange, - update-email, web-authn. + js-adapter, kerberos, map-storage, par, preview, recovery-codes, scripts, + step-up-authentication, token-exchange, update-email, web-authn. --features-disabled Disables a set of one or more features. Possible values are: account-api, account2, account3, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, docker, dynamic-scopes, fips, impersonation, - js-adapter, kerberos, map-storage, openshift-integration, par, preview, - recovery-codes, scripts, step-up-authentication, token-exchange, - update-email, web-authn. + js-adapter, kerberos, map-storage, par, preview, recovery-codes, scripts, + step-up-authentication, token-exchange, update-email, web-authn. Hostname: diff --git a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelp.unix.approved.txt b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelp.unix.approved.txt index 81c34d8155..28bf046220 100644 --- a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelp.unix.approved.txt +++ b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelp.unix.approved.txt @@ -78,17 +78,15 @@ Feature: account2, account3, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, docker, dynamic-scopes, fips, impersonation, - js-adapter, kerberos, map-storage, openshift-integration, par, preview, - recovery-codes, scripts, step-up-authentication, token-exchange, - update-email, web-authn. + js-adapter, kerberos, map-storage, par, preview, recovery-codes, scripts, + step-up-authentication, token-exchange, update-email, web-authn. --features-disabled Disables a set of one or more features. Possible values are: account-api, account2, account3, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, docker, dynamic-scopes, fips, impersonation, - js-adapter, kerberos, map-storage, openshift-integration, par, preview, - recovery-codes, scripts, step-up-authentication, token-exchange, - update-email, web-authn. + js-adapter, kerberos, map-storage, par, preview, recovery-codes, scripts, + step-up-authentication, token-exchange, update-email, web-authn. Hostname: diff --git a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelp.windows.approved.txt b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelp.windows.approved.txt index af3b794098..c7ce90f0de 100644 --- a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelp.windows.approved.txt +++ b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelp.windows.approved.txt @@ -78,17 +78,15 @@ Feature: account2, account3, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, docker, dynamic-scopes, fips, impersonation, - js-adapter, kerberos, map-storage, openshift-integration, par, preview, - recovery-codes, scripts, step-up-authentication, token-exchange, - update-email, web-authn. + js-adapter, kerberos, map-storage, par, preview, recovery-codes, scripts, + step-up-authentication, token-exchange, update-email, web-authn. --features-disabled Disables a set of one or more features. Possible values are: account-api, account2, account3, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, docker, dynamic-scopes, fips, impersonation, - js-adapter, kerberos, map-storage, openshift-integration, par, preview, - recovery-codes, scripts, step-up-authentication, token-exchange, - update-email, web-authn. + js-adapter, kerberos, map-storage, par, preview, recovery-codes, scripts, + step-up-authentication, token-exchange, update-email, web-authn. Hostname: diff --git a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelpAll.unix.approved.txt b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelpAll.unix.approved.txt index d6c6ad88ea..5ed9a222a2 100644 --- a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelpAll.unix.approved.txt +++ b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelpAll.unix.approved.txt @@ -141,17 +141,15 @@ Feature: account2, account3, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, docker, dynamic-scopes, fips, impersonation, - js-adapter, kerberos, map-storage, openshift-integration, par, preview, - recovery-codes, scripts, step-up-authentication, token-exchange, - update-email, web-authn. + js-adapter, kerberos, map-storage, par, preview, recovery-codes, scripts, + step-up-authentication, token-exchange, update-email, web-authn. --features-disabled Disables a set of one or more features. Possible values are: account-api, account2, account3, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, docker, dynamic-scopes, fips, impersonation, - js-adapter, kerberos, map-storage, openshift-integration, par, preview, - recovery-codes, scripts, step-up-authentication, token-exchange, - update-email, web-authn. + js-adapter, kerberos, map-storage, par, preview, recovery-codes, scripts, + step-up-authentication, token-exchange, update-email, web-authn. Hostname: diff --git a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelpAll.windows.approved.txt b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelpAll.windows.approved.txt index 7858f51671..9f15f3d7c0 100644 --- a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelpAll.windows.approved.txt +++ b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelpAll.windows.approved.txt @@ -141,17 +141,15 @@ Feature: account2, account3, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, docker, dynamic-scopes, fips, impersonation, - js-adapter, kerberos, map-storage, openshift-integration, par, preview, - recovery-codes, scripts, step-up-authentication, token-exchange, - update-email, web-authn. + js-adapter, kerberos, map-storage, par, preview, recovery-codes, scripts, + step-up-authentication, token-exchange, update-email, web-authn. --features-disabled Disables a set of one or more features. Possible values are: account-api, account2, account3, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, docker, dynamic-scopes, fips, impersonation, - js-adapter, kerberos, map-storage, openshift-integration, par, preview, - recovery-codes, scripts, step-up-authentication, token-exchange, - update-email, web-authn. + js-adapter, kerberos, map-storage, par, preview, recovery-codes, scripts, + step-up-authentication, token-exchange, update-email, web-authn. Hostname: diff --git a/services/src/main/java/org/keycloak/protocol/openshift/OpenShiftTokenReviewEndpoint.java b/services/src/main/java/org/keycloak/protocol/openshift/OpenShiftTokenReviewEndpoint.java deleted file mode 100644 index 5562bd4626..0000000000 --- a/services/src/main/java/org/keycloak/protocol/openshift/OpenShiftTokenReviewEndpoint.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright 2016 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.openshift; - -import org.keycloak.TokenVerifier; -import org.keycloak.common.Profile; -import org.keycloak.common.VerificationException; -import org.keycloak.crypto.SignatureProvider; -import org.keycloak.crypto.SignatureVerifierContext; -import org.keycloak.events.Details; -import org.keycloak.events.Errors; -import org.keycloak.events.EventBuilder; -import org.keycloak.events.EventType; -import org.keycloak.models.ClientModel; -import org.keycloak.models.KeycloakSession; -import org.keycloak.models.RealmModel; -import org.keycloak.protocol.oidc.TokenManager; -import org.keycloak.protocol.oidc.ext.OIDCExtProvider; -import org.keycloak.protocol.oidc.utils.AuthorizeClientUtil; -import org.keycloak.provider.EnvironmentDependentProviderFactory; -import org.keycloak.representations.AccessToken; -import org.keycloak.services.ErrorResponseException; -import org.keycloak.services.Urls; - -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import java.util.List; - -/** - * @author Bill Burke - * @version $Revision: 1 $ - */ -public class OpenShiftTokenReviewEndpoint implements OIDCExtProvider, EnvironmentDependentProviderFactory { - - private KeycloakSession session; - private TokenManager tokenManager; - private EventBuilder event; - - public OpenShiftTokenReviewEndpoint(KeycloakSession session) { - this.session = session; - this.tokenManager = new TokenManager(); - } - - @Override - public void setEvent(EventBuilder event) { - this.event = event; - } - - @Path("/") - @POST - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - public Response tokenReview(OpenShiftTokenReviewRequestRepresentation reviewRequest) throws Exception { - return tokenReview(null, reviewRequest); - } - - @Path("/{client_id}") - @POST - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - public Response tokenReview(@PathParam("client_id") String clientId, OpenShiftTokenReviewRequestRepresentation reviewRequest) throws Exception { - event.event(EventType.INTROSPECT_TOKEN); - - if (clientId != null) { - session.setAttribute("client_id", clientId); - } - - checkSsl(); - checkRealm(); - authorizeClient(); - - RealmModel realm = session.getContext().getRealm(); - - AccessToken token = null; - try { - TokenVerifier verifier = TokenVerifier.create(reviewRequest.getSpec().getToken(), AccessToken.class) - .realmUrl(Urls.realmIssuer(session.getContext().getUri().getBaseUri(), realm.getName())) - .audience(reviewRequest.getSpec().getAudiences()); - - SignatureVerifierContext verifierContext = session.getProvider(SignatureProvider.class, verifier.getHeader().getAlgorithm().name()).verifier(verifier.getHeader().getKeyId()); - verifier.verifierContext(verifierContext); - - verifier.verify(); - token = verifier.getToken(); - } catch (VerificationException e) { - error(401, Errors.INVALID_TOKEN, "Token verification failure"); - } - - if (!tokenManager.checkTokenValidForIntrospection(session, realm, token, true)) { - error(401, Errors.INVALID_TOKEN, "Token verification failure"); - } - - OpenShiftTokenReviewResponseRepresentation response = new OpenShiftTokenReviewResponseRepresentation(); - response.getStatus().setAuthenticated(true); - response.getStatus().setUser(new OpenShiftTokenReviewResponseRepresentation.User()); - - OpenShiftTokenReviewResponseRepresentation.User userRep = response.getStatus().getUser(); - userRep.setUid(token.getSubject()); - userRep.setUsername(token.getPreferredUsername()); - - if (token.getScope() != null && !token.getScope().isEmpty()) { - OpenShiftTokenReviewResponseRepresentation.Extra extra = new OpenShiftTokenReviewResponseRepresentation.Extra(); - extra.setScopes(token.getScope().split(" ")); - userRep.setExtra(extra); - } - - if (token.getOtherClaims() != null && token.getOtherClaims().get("groups") != null) { - List groups = (List) token.getOtherClaims().get("groups"); - userRep.setGroups(groups); - } - - event.success(); - return Response.ok(response, MediaType.APPLICATION_JSON).build(); - } - - private void checkSsl() { - if (!session.getContext().getUri().getBaseUri().getScheme().equals("https") && session.getContext().getRealm().getSslRequired().isRequired(session.getContext().getConnection())) { - error(401, Errors.SSL_REQUIRED, null); - } - } - - private void checkRealm() { - if (!session.getContext().getRealm().isEnabled()) { - error(401, Errors.REALM_DISABLED,null); - } - } - - private void authorizeClient() { - try { - ClientModel client = AuthorizeClientUtil.authorizeClient(session, event, null).getClient(); - event.client(client); - - if (client == null || client.isPublicClient()) { - error(401, Errors.INVALID_CLIENT, "Public client is not permitted to invoke token review endpoint"); - } - - } catch (ErrorResponseException ere) { - error(401, Errors.INVALID_CLIENT_CREDENTIALS, ere.getErrorDescription()); - } catch (Exception e) { - error(401, Errors.INVALID_CLIENT_CREDENTIALS, null); - } - } - - private void error(int statusCode, String error, String description) { - OpenShiftTokenReviewResponseRepresentation rep = new OpenShiftTokenReviewResponseRepresentation(); - rep.getStatus().setAuthenticated(false); - - Response response = Response.status(statusCode).entity(rep).type(MediaType.APPLICATION_JSON_TYPE).build(); - - event.error(error); - event.detail(Details.REASON, description); - - throw new ErrorResponseException(response); - } - - @Override - public boolean isSupported() { - return Profile.isFeatureEnabled(Profile.Feature.OPENSHIFT_INTEGRATION); - } -} diff --git a/services/src/main/java/org/keycloak/protocol/openshift/OpenShiftTokenReviewEndpointFactory.java b/services/src/main/java/org/keycloak/protocol/openshift/OpenShiftTokenReviewEndpointFactory.java deleted file mode 100644 index a58b8cedcd..0000000000 --- a/services/src/main/java/org/keycloak/protocol/openshift/OpenShiftTokenReviewEndpointFactory.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2016 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.openshift; - -import org.keycloak.common.Profile; -import org.keycloak.models.KeycloakSession; -import org.keycloak.protocol.oidc.ext.OIDCExtProvider; -import org.keycloak.protocol.oidc.ext.OIDCExtProviderFactory; -import org.keycloak.provider.EnvironmentDependentProviderFactory; - -/** - * @author Bill Burke - * @version $Revision: 1 $ - */ -public class OpenShiftTokenReviewEndpointFactory implements OIDCExtProviderFactory, EnvironmentDependentProviderFactory { - - @Override - public OIDCExtProvider create(KeycloakSession session) { - return new OpenShiftTokenReviewEndpoint(session); - } - - @Override - public String getId() { - return "openshift-token-review"; - } - - @Override - public boolean isSupported() { - return Profile.isFeatureEnabled(Profile.Feature.OPENSHIFT_INTEGRATION); - } - -} diff --git a/services/src/main/java/org/keycloak/protocol/openshift/OpenShiftTokenReviewRequestRepresentation.java b/services/src/main/java/org/keycloak/protocol/openshift/OpenShiftTokenReviewRequestRepresentation.java deleted file mode 100755 index dd0faaacfd..0000000000 --- a/services/src/main/java/org/keycloak/protocol/openshift/OpenShiftTokenReviewRequestRepresentation.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2016 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.openshift; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.io.Serializable; - -/** - * @author Bill Burke - * @version $Revision: 1 $ - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class OpenShiftTokenReviewRequestRepresentation implements Serializable { - - @JsonProperty("apiVersion") - private String apiVersion = "authentication.k8s.io/v1beta1"; - - @JsonProperty("kind") - private String kind = "TokenReview"; - - @JsonProperty("spec") - private Spec spec; - - public String getApiVersion() { - return apiVersion; - } - - public void setApiVersion(String apiVersion) { - this.apiVersion = apiVersion; - } - - public String getKind() { - return kind; - } - - public void setKind(String kind) { - this.kind = kind; - } - - public Spec getSpec() { - return spec; - } - - public void setSpec(Spec spec) { - this.spec = spec; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static class Spec implements Serializable { - - @JsonProperty("token") - private String token; - - @JsonProperty("audiences") - private String[] audiences; - - public String getToken() { - return token; - } - - public void setToken(String token) { - this.token = token; - } - - public String[] getAudiences() { - return audiences; - } - - public void setAudiences(String[] audiences) { - this.audiences = audiences; - } - } - -} diff --git a/services/src/main/java/org/keycloak/protocol/openshift/OpenShiftTokenReviewResponseRepresentation.java b/services/src/main/java/org/keycloak/protocol/openshift/OpenShiftTokenReviewResponseRepresentation.java deleted file mode 100755 index 63422aa30a..0000000000 --- a/services/src/main/java/org/keycloak/protocol/openshift/OpenShiftTokenReviewResponseRepresentation.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright 2016 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.openshift; - -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.io.Serializable; -import java.util.LinkedList; -import java.util.List; - -/** - * @author Bill Burke - * @version $Revision: 1 $ - */ -public class OpenShiftTokenReviewResponseRepresentation implements Serializable { - - @JsonProperty("apiVersion") - private String apiVersion = "authentication.k8s.io/v1beta1"; - - @JsonProperty("kind") - private String kind = "TokenReview"; - - @JsonProperty("status") - private Status status = new Status(); - - public Status getStatus() { - return status; - } - - public void setStatus(Status status) { - this.status = status; - } - - public String getApiVersion() { - return apiVersion; - } - - public void setApiVersion(String apiVersion) { - this.apiVersion = apiVersion; - } - - public String getKind() { - return kind; - } - - public void setKind(String kind) { - this.kind = kind; - } - - public static class Status implements Serializable { - - @JsonProperty("authenticated") - private boolean authenticated; - - @JsonProperty("user") - protected User user; - - public boolean isAuthenticated() { - return authenticated; - } - - public void setAuthenticated(boolean authenticated) { - this.authenticated = authenticated; - } - - public User getUser() { - return user; - } - - public void setUser(User user) { - this.user = user; - } - - } - - public static class User implements Serializable { - - @JsonProperty("username") - protected String username; - - @JsonProperty("uid") - protected String uid; - - @JsonProperty("groups") - protected List groups = new LinkedList<>(); - - @JsonProperty("extra") - protected Extra extra; - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getUid() { - return uid; - } - - public void setUid(String uid) { - this.uid = uid; - } - - public List getGroups() { - return groups; - } - - public void setGroups(List groups) { - this.groups = groups; - } - - public Extra getExtra() { - return extra; - } - - public void setExtra(Extra extra) { - this.extra = extra; - } - - } - - public static class Extra implements Serializable { - - @JsonProperty("scopes.authorization.openshift.io") - private String[] scopes; - - public String[] getScopes() { - return scopes; - } - - public void setScopes(String[] scopes) { - this.scopes = scopes; - } - } - -} diff --git a/services/src/main/resources/META-INF/services/org.keycloak.protocol.oidc.ext.OIDCExtProviderFactory b/services/src/main/resources/META-INF/services/org.keycloak.protocol.oidc.ext.OIDCExtProviderFactory index 29f6126cb2..2f73e1f3eb 100644 --- a/services/src/main/resources/META-INF/services/org.keycloak.protocol.oidc.ext.OIDCExtProviderFactory +++ b/services/src/main/resources/META-INF/services/org.keycloak.protocol.oidc.ext.OIDCExtProviderFactory @@ -1,3 +1,2 @@ -org.keycloak.protocol.openshift.OpenShiftTokenReviewEndpointFactory org.keycloak.protocol.oidc.grants.ciba.endpoints.CibaRootEndpoint org.keycloak.protocol.oidc.par.endpoints.ParRootEndpoint \ No newline at end of file diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/federation/HardcodedGroupStorageProvider.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/federation/HardcodedGroupStorageProvider.java index a4c6dde08e..ceef6ce6fa 100644 --- a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/federation/HardcodedGroupStorageProvider.java +++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/federation/HardcodedGroupStorageProvider.java @@ -16,7 +16,6 @@ */ package org.keycloak.testsuite.federation; -import org.apache.commons.lang.BooleanUtils; import org.jboss.logging.Logger; import org.keycloak.models.ClientModel; import org.keycloak.models.GroupModel; @@ -61,7 +60,7 @@ public class HardcodedGroupStorageProvider implements GroupStorageProvider { Logger.getLogger(HardcodedGroupStorageProvider.class).warn(ex.getCause()); return Stream.empty(); } - if(BooleanUtils.isTrue(exact)){ + if(exact != null && exact){ if (search != null && this.groupName.equals(search)) { return Stream.of(new HardcodedGroupAdapter(realm)); } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/openshift/OpenShiftTokenReviewEndpointTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/openshift/OpenShiftTokenReviewEndpointTest.java deleted file mode 100644 index f3f2569146..0000000000 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/openshift/OpenShiftTokenReviewEndpointTest.java +++ /dev/null @@ -1,502 +0,0 @@ -/* - * Copyright 2018 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.openshift; - -import org.apache.http.Header; -import org.apache.http.HeaderElement; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.util.EntityUtils; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.keycloak.OAuth2Constants; -import org.keycloak.admin.client.resource.ClientResource; -import org.keycloak.admin.client.resource.RealmResource; -import org.keycloak.authentication.authenticators.client.ClientIdAndSecretAuthenticator; -import org.keycloak.common.util.Base64Url; -import org.keycloak.crypto.Algorithm; -import org.keycloak.events.Details; -import org.keycloak.jose.jws.JWSInput; -import org.keycloak.protocol.oidc.OIDCConfigAttributes; -import org.keycloak.protocol.oidc.OIDCLoginProtocol; -import org.keycloak.protocol.oidc.mappers.GroupMembershipMapper; -import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper; -import org.keycloak.protocol.openshift.OpenShiftTokenReviewRequestRepresentation; -import org.keycloak.protocol.openshift.OpenShiftTokenReviewResponseRepresentation; -import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation; -import org.keycloak.representations.idm.ClientRepresentation; -import org.keycloak.representations.idm.ClientScopeRepresentation; -import org.keycloak.representations.idm.EventRepresentation; -import org.keycloak.representations.idm.ProtocolMapperRepresentation; -import org.keycloak.representations.idm.RealmRepresentation; -import org.keycloak.testsuite.AbstractTestRealmKeycloakTest; -import org.keycloak.testsuite.AssertEvents; -import org.keycloak.testsuite.admin.ApiUtil; -import org.keycloak.testsuite.arquillian.annotation.EnableFeature; -import org.keycloak.testsuite.util.OAuthClient; -import org.keycloak.testsuite.util.UserBuilder; -import org.keycloak.util.JsonSerialization; - -import jakarta.ws.rs.core.HttpHeaders; -import jakarta.ws.rs.core.Response; -import java.io.IOException; -import java.util.Arrays; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.keycloak.common.Profile.Feature.OPENSHIFT_INTEGRATION; -import static org.keycloak.testsuite.util.ServerURLs.getAuthServerContextRoot; -import static org.keycloak.utils.MediaType.APPLICATION_JSON; - -@EnableFeature(value = OPENSHIFT_INTEGRATION, skipRestart = true) -public class OpenShiftTokenReviewEndpointTest extends AbstractTestRealmKeycloakTest { - - private static boolean flowConfigured; - - @Rule - public AssertEvents events = new AssertEvents(this); - - @Override - public void configureTestRealm(RealmRepresentation testRealm) { - ClientRepresentation client = testRealm.getClients().stream().filter(r -> r.getClientId().equals("test-app")).findFirst().get(); - - List mappers = new LinkedList<>(); - ProtocolMapperRepresentation mapper = new ProtocolMapperRepresentation(); - mapper.setName("groups"); - mapper.setProtocolMapper(GroupMembershipMapper.PROVIDER_ID); - mapper.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL); - Map config = new HashMap<>(); - config.put("full.path", "false"); - config.put(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME, "groups"); - config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN, "true"); - config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN, "true"); - mapper.setConfig(config); - mappers.add(mapper); - - client.setProtocolMappers(mappers); - client.setPublicClient(false); - client.setClientAuthenticatorType("testsuite-client-dummy"); - - testRealm.getUsers().add( - UserBuilder.create() - .username("groups-user") - .password("password") - .addGroups("/topGroup", "/topGroup/level2group") - .role("account", "view-profile") - .build()); - - testRealm.getUsers().add( - UserBuilder.create() - .username("empty-audience") - .password("password") - .build()); - } - - @Before - public void enablePassthroughAuthenticator() { - if (!flowConfigured) { - HashMap data = new HashMap<>(); - data.put("newName", "testsuite-client-dummy"); - Response response = testRealm().flows().copy("clients", data); - assertEquals(201, response.getStatus()); - response.close(); - - data = new HashMap<>(); - data.put("provider", "testsuite-client-dummy"); - data.put("requirement", "ALTERNATIVE"); - - testRealm().flows().addExecution("testsuite-client-dummy", data); - - RealmRepresentation realmRep = testRealm().toRepresentation(); - realmRep.setClientAuthenticationFlow("testsuite-client-dummy"); - testRealm().update(realmRep); - - List executions = testRealm().flows().getExecutions("testsuite-client-dummy"); - for (AuthenticationExecutionInfoRepresentation e : executions) { - if (e.getProviderId().equals("testsuite-client-dummy")) { - e.setRequirement("ALTERNATIVE"); - testRealm().flows().updateExecutions("testsuite-client-dummy", e); - } - } - flowConfigured = true; - } - } - - @Test - public void basicTest() { - Review r = new Review().invoke(); - - String userId = testRealm().users().search(r.username).get(0).getId(); - - OpenShiftTokenReviewResponseRepresentation.User user = r.response.getStatus().getUser(); - - assertEquals(userId, user.getUid()); - assertEquals("test-user@localhost", user.getUsername()); - assertNotNull(user.getExtra()); - - r.assertScope("openid", "email", "profile"); - } - - @Test - public void longExpiration() { - ClientResource client = ApiUtil.findClientByClientId(adminClient.realm("test"), "test-app"); - ClientRepresentation clientRep = client.toRepresentation(); - - try { - clientRep.getAttributes().put(OIDCConfigAttributes.ACCESS_TOKEN_LIFESPAN, "-1"); - client.update(clientRep); - - // Set time offset just before SSO idle, to get session last refresh updated - - setTimeOffset(1500); - - Review review = new Review(); - - review.invoke().assertSuccess(); - - // Bump last refresh updated again - - setTimeOffset(3000); - - review.invoke().assertSuccess(); - - // And, again - - setTimeOffset(4500); - - // Token should still be valid as session last refresh should have been updated - - review.invoke().assertSuccess(); - } finally { - clientRep.getAttributes().put(OIDCConfigAttributes.ACCESS_TOKEN_LIFESPAN, null); - client.update(clientRep); - } - } - - @Test - public void hs256() { - RealmResource realm = adminClient.realm("test"); - RealmRepresentation rep = realm.toRepresentation(); - - try { - rep.setDefaultSignatureAlgorithm(Algorithm.HS256); - realm.update(rep); - - Review r = new Review().algorithm(Algorithm.HS256).invoke() - .assertSuccess(); - - String userId = testRealm().users().search(r.username).get(0).getId(); - - OpenShiftTokenReviewResponseRepresentation.User user = r.response.getStatus().getUser(); - - assertEquals(userId, user.getUid()); - assertEquals("test-user@localhost", user.getUsername()); - assertNotNull(user.getExtra()); - - r.assertScope("openid", "email", "profile"); - } finally { - rep.setDefaultSignatureAlgorithm(null); - realm.update(rep); - } - } - - @Test - public void groups() { - new Review().username("groups-user") - .invoke() - .assertSuccess().assertGroups("topGroup", "level2group"); - } - - @Test - public void customScopes() { - ClientScopeRepresentation clientScope = new ClientScopeRepresentation(); - clientScope.setProtocol("openid-connect"); - clientScope.setName("user:info"); - - String id; - try (Response r = testRealm().clientScopes().create(clientScope)) { - id = ApiUtil.getCreatedId(r); - } - - ClientRepresentation clientRep = testRealm().clients().findByClientId("test-app").get(0); - - testRealm().clients().get(clientRep.getId()).addOptionalClientScope(id); - - try { - oauth.scope("user:info"); - new Review() - .invoke() - .assertSuccess().assertScope("openid", "user:info", "profile", "email"); - } finally { - testRealm().clients().get(clientRep.getId()).removeOptionalClientScope(id); - } - } - - @Test - public void emptyAudience() { - new Review().username("empty-audience") - .invoke() - .assertError(401, "Token verification failure"); - } - - @Test - public void expiredToken() { - try { - new Review() - .runAfterTokenRequest(i -> setTimeOffset(testRealm().toRepresentation().getAccessTokenLifespan() + 10)) - .invoke() - .assertError(401, "Token verification failure"); - } finally { - resetTimeOffset(); - } - } - - @Test - public void invalidPublicKey() { - new Review() - .runAfterTokenRequest(i -> { - String header = i.token.split("\\.")[0]; - String s = new String(Base64Url.decode(header)); - s = s.replace(",\"kid\" : \"", ",\"kid\" : \"x"); - String newHeader = Base64Url.encode(s.getBytes()); - i.token = i.token.replaceFirst(header, newHeader); - }) - .invoke() - .assertError(401, "Token verification failure"); - } - - @Test - public void noUserSession() { - new Review() - .runAfterTokenRequest(i -> { - String userId = testRealm().users().search(i.username).get(0).getId(); - testRealm().users().get(userId).logout(); - }) - .invoke() - .assertError(401, "Token verification failure"); - } - - @Test - public void invalidTokenSignature() { - new Review() - .runAfterTokenRequest(i -> i.token += "x") - .invoke() - .assertError(401, "Token verification failure"); - } - - @Test - public void realmDisabled() { - RealmRepresentation r = testRealm().toRepresentation(); - try { - new Review().runAfterTokenRequest(i -> { - r.setEnabled(false); - testRealm().update(r); - }).invoke().assertError(401, null); - - - } finally { - r.setEnabled(true); - testRealm().update(r); - } - } - - @Test - public void publicClientNotPermitted() { - ClientRepresentation clientRep = testRealm().clients().findByClientId("test-app").get(0); - clientRep.setPublicClient(true); - testRealm().clients().get(clientRep.getId()).update(clientRep); - try { - new Review() - .clientAuthMethod(ClientIdAndSecretAuthenticator.PROVIDER_ID) - .invoke().assertError(401, "Public client is not permitted to invoke token review endpoint"); - } finally { - clientRep.setPublicClient(false); - clientRep.setSecret("password"); - testRealm().clients().get(clientRep.getId()).update(clientRep); - } - } - - @Test - public void checkPropertyValidation() throws IOException { - try (CloseableHttpClient client = HttpClientBuilder.create().build()) { - String url = getAuthServerContextRoot() + "/auth/realms/" + "test" + "/protocol/openid-connect/ext/openshift-token-review/"; - - HttpPost post = new HttpPost(url); - post.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()); - post.setHeader(HttpHeaders.ACCEPT, ContentType.APPLICATION_JSON.toString()); - post.setEntity(new StringEntity("{\"\":1}")); - - try (CloseableHttpResponse response = client.execute(post)) { - Header header = response.getFirstHeader("Content-Type"); - assertThat(header, notNullValue()); - - // Verify the Content-Type is not text/html - assertThat(Arrays.stream(header.getElements()) - .map(HeaderElement::getName) - .filter(Objects::nonNull) - .anyMatch(f -> f.equals(APPLICATION_JSON)), is(true)); - - // OpenShiftTokenReviewRequestRepresentation ignore unknown attributes and is returned default representation - assertThat(EntityUtils.toString(response.getEntity()).contains("Unrecognized field \\\"\\\""), is(false)); - } - } - } - - private class Review { - - private String realm = "test"; - private String clientId = "test-app"; - private String username = "test-user@localhost"; - private String password = "password"; - private String algorithm = Algorithm.RS256; - private InvokeRunnable runAfterTokenRequest; - - private String token; - private String clientAuthMethod = "testsuite-client-dummy"; - private int responseStatus; - private OpenShiftTokenReviewResponseRepresentation response; - - public Review username(String username) { - this.username = username; - return this; - } - - public Review algorithm(String algorithm) { - this.algorithm = algorithm; - return this; - } - - public Review clientAuthMethod(String clientAuthMethod) { - this.clientAuthMethod = clientAuthMethod; - return this; - } - - public Review runAfterTokenRequest(InvokeRunnable runnable) { - this.runAfterTokenRequest = runnable; - return this; - } - - public Review invoke() { - try { - if (token == null) { - String userId = testRealm().users().search(username).get(0).getId(); - oauth.doLogin(username, password); - EventRepresentation loginEvent = events.expectLogin().user(userId).assertEvent(); - - String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE); - OAuthClient.AccessTokenResponse accessTokenResponse = oauth.doAccessTokenRequest(code, "password"); - - events.expectCodeToToken(loginEvent.getDetails().get(Details.CODE_ID), loginEvent.getSessionId()).detail("client_auth_method", this.clientAuthMethod).user(userId).assertEvent(); - - token = accessTokenResponse.getAccessToken(); - } - - assertEquals(algorithm, new JWSInput(token).getHeader().getAlgorithm().name()); - - if (runAfterTokenRequest != null) { - runAfterTokenRequest.run(this); - } - - try (CloseableHttpClient client = HttpClientBuilder.create().build()) { - String url = getAuthServerContextRoot() + "/auth/realms/" + realm + "/protocol/openid-connect/ext/openshift-token-review/" + clientId; - - OpenShiftTokenReviewRequestRepresentation request = new OpenShiftTokenReviewRequestRepresentation(); - OpenShiftTokenReviewRequestRepresentation.Spec spec = new OpenShiftTokenReviewRequestRepresentation.Spec(); - spec.setToken(token); - spec.setAudiences(new String[]{"account"}); - request.setSpec(spec); - - HttpPost post = new HttpPost(url); - post.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()); - post.setHeader(HttpHeaders.ACCEPT, ContentType.APPLICATION_JSON.toString()); - post.setEntity(new StringEntity(JsonSerialization.writeValueAsString(request))); - - try (CloseableHttpResponse resp = client.execute(post)) { - responseStatus = resp.getStatusLine().getStatusCode(); - response = JsonSerialization.readValue(resp.getEntity().getContent(), OpenShiftTokenReviewResponseRepresentation.class); - } - - assertEquals("authentication.k8s.io/v1beta1", response.getApiVersion()); - assertEquals("TokenReview", response.getKind()); - } - return this; - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - public Review assertSuccess() { - assertEquals(200, responseStatus); - assertTrue(response.getStatus().isAuthenticated()); - assertNotNull(response.getStatus().getUser()); - return this; - } - - private Review assertError(int expectedStatus, String expectedReason) { - assertEquals(expectedStatus, responseStatus); - assertFalse(response.getStatus().isAuthenticated()); - assertNull(response.getStatus().getUser()); - - if (expectedReason != null) { - EventRepresentation poll = events.poll(); - assertEquals(expectedReason, poll.getDetails().get(Details.REASON)); - } - - return this; - } - - private void assertScope(String... expectedScope) { - List actualScopes = Arrays.asList(response.getStatus().getUser().getExtra().getScopes()); - assertEquals(expectedScope.length, actualScopes.size()); - assertThat(actualScopes, containsInAnyOrder(expectedScope)); - } - - private void assertEmptyScope() { - assertNull(response.getStatus().getUser().getExtra()); - } - - private void assertGroups(String... expectedGroups) { - List actualGroups = new LinkedList<>(response.getStatus().getUser().getGroups()); - assertEquals(expectedGroups.length, actualGroups.size()); - assertThat(actualGroups, containsInAnyOrder(expectedGroups)); - } - - } - - private interface InvokeRunnable { - void run(Review i); - } - -} diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/openshift/OpenshiftClientStorageTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/openshift/OpenshiftClientStorageTest.java deleted file mode 100644 index 62b8b63b51..0000000000 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/openshift/OpenshiftClientStorageTest.java +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Copyright 2018 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.openshift; - -import io.undertow.Undertow; -import io.undertow.server.HttpHandler; -import io.undertow.server.HttpServerExchange; -import org.jboss.arquillian.graphene.page.Page; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Rule; -import org.junit.Test; -import org.keycloak.OAuth2Constants; -import org.keycloak.OAuthErrorException; -import org.keycloak.admin.client.resource.ComponentResource; -import org.keycloak.common.Profile.Feature; -import org.keycloak.common.util.MultivaluedHashMap; -import org.keycloak.common.util.StreamUtil; -import org.keycloak.events.Details; -import org.keycloak.jose.jws.JWSInput; -import org.keycloak.representations.AccessToken; -import org.keycloak.representations.idm.ComponentRepresentation; -import org.keycloak.representations.idm.RealmRepresentation; -import org.keycloak.storage.client.ClientStorageProvider; -import org.keycloak.storage.openshift.OpenshiftClientStorageProviderFactory; -import org.keycloak.testsuite.AbstractTestRealmKeycloakTest; -import org.keycloak.testsuite.AssertEvents; -import org.keycloak.testsuite.ProfileAssume; -import org.keycloak.testsuite.admin.ApiUtil; -import org.keycloak.testsuite.arquillian.annotation.EnableFeature; -import org.keycloak.testsuite.pages.AppPage; -import org.keycloak.testsuite.pages.ConsentPage; -import org.keycloak.testsuite.pages.ErrorPage; -import org.keycloak.testsuite.pages.LoginPage; -import org.keycloak.testsuite.util.OAuthClient; - -import jakarta.ws.rs.core.Response; -import java.io.IOException; -import java.util.Arrays; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; -import static org.keycloak.common.Profile.Feature.OPENSHIFT_INTEGRATION; -import static org.keycloak.testsuite.ProfileAssume.assumeFeatureEnabled; -import static org.keycloak.testsuite.admin.ApiUtil.findUserByUsername; - -/** - * Test that clients can override auth flows - * - * @author Pedro Igor - */ -@EnableFeature(value = OPENSHIFT_INTEGRATION, skipRestart = true) -public final class OpenshiftClientStorageTest extends AbstractTestRealmKeycloakTest { - - private static Undertow OPENSHIFT_API_SERVER; - - @Rule - public AssertEvents events = new AssertEvents(this); - - @Page - private LoginPage loginPage; - - @Page - private AppPage appPage; - - @Page - private ConsentPage consentPage; - - @Page - private ErrorPage errorPage; - - private String userId; - private String clientStorageId; - - @Override - public void configureTestRealm(RealmRepresentation testRealm) { - } - - @BeforeClass - public static void checkNotMapStorage() { - ProfileAssume.assumeFeatureDisabled(Feature.MAP_STORAGE); - } - - @BeforeClass - public static void onBeforeClass() { - OPENSHIFT_API_SERVER = Undertow.builder().addHttpListener(8880, "localhost", new HttpHandler() { - @Override - public void handleRequest(HttpServerExchange exchange) throws Exception { - String uri = exchange.getRequestURI(); - - if (uri.endsWith("/version/openshift") || uri.endsWith("/version")) { - writeResponse("openshift-version.json", exchange); - } else if (uri.endsWith("/oapi")) { - writeResponse("oapi-response.json", exchange); - } else if (uri.endsWith("/apis")) { - writeResponse("apis-response.json", exchange); - } else if (uri.endsWith("/api")) { - writeResponse("api.json", exchange); - } else if (uri.endsWith("/api/v1")) { - writeResponse("api-v1.json", exchange); - } else if (uri.endsWith("/oapi/v1")) { - writeResponse("oapi-v1.json", exchange); - } else if (uri.contains("/apis/route.openshift.io/v1")) { - writeResponse("apis-route-v1.json", exchange); - } else if (uri.endsWith("/api/v1/namespaces/default")) { - writeResponse("namespace-default.json", exchange); - } else if (uri.endsWith("/oapi/v1/namespaces/default/routes/proxy")) { - writeResponse("route-response.json", exchange); - } else if (uri.contains("/serviceaccounts/system")) { - writeResponse("sa-system.json", exchange); - } else if (uri.contains("/serviceaccounts/")) { - writeResponse(uri.substring(uri.lastIndexOf('/') + 1) + ".json", exchange); - } - } - - private void writeResponse(String file, HttpServerExchange exchange) throws IOException { - exchange.getResponseSender().send(StreamUtil.readString(getClass().getResourceAsStream("/openshift/client-storage/" + file))); - } - }).build(); - - OPENSHIFT_API_SERVER.start(); - } - - @AfterClass - public static void onAfterClass() { - if (OPENSHIFT_API_SERVER != null) { - OPENSHIFT_API_SERVER.stop(); - } - } - - @Before - public void onBefore() { - assumeFeatureEnabled(OPENSHIFT_INTEGRATION); - ComponentRepresentation provider = new ComponentRepresentation(); - - provider.setName("openshift-client-storage"); - provider.setProviderId(OpenshiftClientStorageProviderFactory.PROVIDER_ID); - provider.setProviderType(ClientStorageProvider.class.getName()); - provider.setConfig(new MultivaluedHashMap<>()); - provider.getConfig().putSingle(OpenshiftClientStorageProviderFactory.CONFIG_PROPERTY_OPENSHIFT_URI, "http://localhost:8880"); - provider.getConfig().putSingle(OpenshiftClientStorageProviderFactory.CONFIG_PROPERTY_ACCESS_TOKEN, "token"); - provider.getConfig().putSingle(OpenshiftClientStorageProviderFactory.CONFIG_PROPERTY_DEFAULT_NAMESPACE, "default"); - provider.getConfig().putSingle(OpenshiftClientStorageProviderFactory.CONFIG_PROPERTY_REQUIRE_USER_CONSENT, "true"); - - Response resp = adminClient.realm("test").components().add(provider); - resp.close(); - clientStorageId = ApiUtil.getCreatedId(resp); - getCleanup().addComponentId(clientStorageId); - } - - @Before - public void clientConfiguration() { - userId = findUserByUsername(adminClient.realm("test"), "test-user@localhost").getId(); - } - - @Test - public void testCodeGrantFlowWithServiceAccountUsingOAuthRedirectReference() { - String clientId = "system:serviceaccount:default:sa-oauth-redirect-reference"; - testCodeGrantFlow(clientId, "http://127.0.0.1:8180/callback", () -> assertSuccessfulResponseWithoutConsent(clientId)); - } - - @Test - public void failCodeGrantFlowWithServiceAccountUsingOAuthRedirectReference() throws Exception { - testCodeGrantFlow("system:serviceaccount:default:sa-oauth-redirect-reference", "http://invalid/callback", () -> assertEquals(OAuthErrorException.INVALID_REDIRECT_URI, events.poll().getError())); - } - - @Test - public void testCodeGrantFlowWithServiceAccountUsingOAuthRedirectUri() { - String clientId = "system:serviceaccount:default:sa-oauth-redirect-uri"; - testCodeGrantFlow(clientId, "http://localhost:8180/auth/realms/master/app/auth", () -> assertSuccessfulResponseWithoutConsent(clientId)); - testCodeGrantFlow(clientId, "http://localhost:8180/auth/realms/master/app/auth/second", () -> assertSuccessfulResponseWithoutConsent(clientId)); - testCodeGrantFlow(clientId, "http://localhost:8180/auth/realms/master/app/auth/third", () -> assertSuccessfulResponseWithoutConsent(clientId)); - } - - @Test - public void testCodeGrantFlowWithUserConsent() { - String clientId = "system:serviceaccount:default:sa-oauth-redirect-uri"; - testCodeGrantFlow(clientId, "http://localhost:8180/auth/realms/master/app/auth", () -> assertSuccessfulResponseWithConsent(clientId), "user:info user:check-access"); - - ComponentResource component = testRealm().components().component(clientStorageId); - ComponentRepresentation representation = component.toRepresentation(); - - representation.getConfig().put(OpenshiftClientStorageProviderFactory.CONFIG_PROPERTY_REQUIRE_USER_CONSENT, Arrays.asList("false")); - component.update(representation); - - testCodeGrantFlow(clientId, "http://localhost:8180/auth/realms/master/app/auth", () -> assertSuccessfulResponseWithoutConsent(clientId), "user:info user:check-access"); - - representation.getConfig().put(OpenshiftClientStorageProviderFactory.CONFIG_PROPERTY_REQUIRE_USER_CONSENT, Arrays.asList("true")); - component.update(representation); - - testCodeGrantFlow(clientId, "http://localhost:8180/auth/realms/master/app/auth", () -> assertSuccessfulResponseWithoutConsent(clientId, Details.CONSENT_VALUE_PERSISTED_CONSENT), "user:info user:check-access"); - - testRealm().users().get(userId).revokeConsent(clientId); - - testCodeGrantFlow(clientId, "http://localhost:8180/auth/realms/master/app/auth", () -> assertSuccessfulResponseWithConsent(clientId), "user:info user:check-access"); - } - - @Test - public void failCodeGrantFlowWithServiceAccountUsingOAuthRedirectUri() throws Exception { - testCodeGrantFlow("system:serviceaccount:default:sa-oauth-redirect-uri", "http://invalid/callback", () -> assertEquals(OAuthErrorException.INVALID_REDIRECT_URI, events.poll().getError())); - } - - private void testCodeGrantFlow(String clientId, String expectedRedirectUri, Runnable assertThat) { - testCodeGrantFlow(clientId, expectedRedirectUri, assertThat, null); - } - - private void testCodeGrantFlow(String clientId, String expectedRedirectUri, Runnable assertThat, String scope) { - if (scope != null) { - oauth.scope(scope); - } - oauth.clientId(clientId); - oauth.redirectUri(expectedRedirectUri); - driver.navigate().to(oauth.getLoginFormUrl()); - loginPage.assertCurrent(); - - try { - // Fill username+password. I am successfully authenticated - oauth.fillLoginForm("test-user@localhost", "password"); - } catch (Exception ignore) { - - } - - assertThat.run(); - } - - private void assertSuccessfulResponseWithoutConsent(String clientId) { - assertSuccessfulResponseWithoutConsent(clientId, null); - } - - private void assertSuccessfulResponseWithoutConsent(String clientId, String consentDetail) { - AssertEvents.ExpectedEvent expectedEvent = events.expectLogin().client(clientId).detail(Details.REDIRECT_URI, oauth.getRedirectUri()).detail(Details.USERNAME, "test-user@localhost"); - - if (consentDetail != null) { - expectedEvent.detail(Details.CONSENT, Details.CONSENT_VALUE_PERSISTED_CONSENT); - } - - expectedEvent.assertEvent(); - assertSuccessfulRedirect(); - } - - private void assertSuccessfulResponseWithConsent(String clientId) { - consentPage.assertCurrent(); - driver.getPageSource().contains("user:info"); - driver.getPageSource().contains("user:check-access"); - consentPage.confirm(); - events.expectLogin().client(clientId).detail(Details.REDIRECT_URI, oauth.getRedirectUri()).detail(Details.USERNAME, "test-user@localhost").detail(Details.CONSENT, Details.CONSENT_VALUE_CONSENT_GRANTED).assertEvent(); - assertSuccessfulRedirect("user:info", "user:check-access"); - } - - private void assertSuccessfulRedirect(String... expectedScopes) { - String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE); - OAuthClient.AccessTokenResponse tokenResponse = oauth.doAccessTokenRequest(code, null); - String accessToken = tokenResponse.getAccessToken(); - Assert.assertNotNull(accessToken); - - try { - AccessToken token = new JWSInput(accessToken).readJsonContent(AccessToken.class); - - for (String expectedScope : expectedScopes) { - token.getScope().contains(expectedScope); - } - } catch (Exception e) { - fail("Failed to parse access token"); - e.printStackTrace(); - } - - Assert.assertNotNull(tokenResponse.getRefreshToken()); - oauth.doLogout(tokenResponse.getRefreshToken(), null); - events.clear(); - } -} diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/api-v1.json b/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/api-v1.json deleted file mode 100644 index ca080238da..0000000000 --- a/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/api-v1.json +++ /dev/null @@ -1,495 +0,0 @@ -{ - "kind": "APIResourceList", - "groupVersion": "v1", - "resources": [ - { - "name": "bindings", - "singularName": "", - "namespaced": true, - "kind": "Binding", - "verbs": [ - "create" - ] - }, - { - "name": "componentstatuses", - "singularName": "", - "namespaced": false, - "kind": "ComponentStatus", - "verbs": [ - "get", - "list" - ], - "shortNames": [ - "cs" - ] - }, - { - "name": "configmaps", - "singularName": "", - "namespaced": true, - "kind": "ConfigMap", - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update", - "watch" - ], - "shortNames": [ - "cm" - ] - }, - { - "name": "endpoints", - "singularName": "", - "namespaced": true, - "kind": "Endpoints", - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update", - "watch" - ], - "shortNames": [ - "ep" - ] - }, - { - "name": "events", - "singularName": "", - "namespaced": true, - "kind": "Event", - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update", - "watch" - ], - "shortNames": [ - "ev" - ] - }, - { - "name": "limitranges", - "singularName": "", - "namespaced": true, - "kind": "LimitRange", - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update", - "watch" - ], - "shortNames": [ - "limits" - ] - }, - { - "name": "namespaces", - "singularName": "", - "namespaced": false, - "kind": "Namespace", - "verbs": [ - "create", - "delete", - "get", - "list", - "patch", - "update", - "watch" - ], - "shortNames": [ - "ns" - ] - }, - { - "name": "namespaces/finalize", - "singularName": "", - "namespaced": false, - "kind": "Namespace", - "verbs": [ - "update" - ] - }, - { - "name": "namespaces/status", - "singularName": "", - "namespaced": false, - "kind": "Namespace", - "verbs": [ - "get", - "patch", - "update" - ] - }, - { - "name": "nodes", - "singularName": "", - "namespaced": false, - "kind": "Node", - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update", - "watch" - ], - "shortNames": [ - "no" - ] - }, - { - "name": "nodes/proxy", - "singularName": "", - "namespaced": false, - "kind": "Node", - "verbs": [] - }, - { - "name": "nodes/status", - "singularName": "", - "namespaced": false, - "kind": "Node", - "verbs": [ - "get", - "patch", - "update" - ] - }, - { - "name": "persistentvolumeclaims", - "singularName": "", - "namespaced": true, - "kind": "PersistentVolumeClaim", - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update", - "watch" - ], - "shortNames": [ - "pvc" - ] - }, - { - "name": "persistentvolumeclaims/status", - "singularName": "", - "namespaced": true, - "kind": "PersistentVolumeClaim", - "verbs": [ - "get", - "patch", - "update" - ] - }, - { - "name": "persistentvolumes", - "singularName": "", - "namespaced": false, - "kind": "PersistentVolume", - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update", - "watch" - ], - "shortNames": [ - "pv" - ] - }, - { - "name": "persistentvolumes/status", - "singularName": "", - "namespaced": false, - "kind": "PersistentVolume", - "verbs": [ - "get", - "patch", - "update" - ] - }, - { - "name": "pods", - "singularName": "", - "namespaced": true, - "kind": "Pod", - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update", - "watch" - ], - "shortNames": [ - "po" - ], - "categories": [ - "all" - ] - }, - { - "name": "pods/attach", - "singularName": "", - "namespaced": true, - "kind": "Pod", - "verbs": [] - }, - { - "name": "pods/binding", - "singularName": "", - "namespaced": true, - "kind": "Binding", - "verbs": [ - "create" - ] - }, - { - "name": "pods/eviction", - "singularName": "", - "namespaced": true, - "group": "policy", - "version": "v1beta1", - "kind": "Eviction", - "verbs": [ - "create" - ] - }, - { - "name": "pods/exec", - "singularName": "", - "namespaced": true, - "kind": "Pod", - "verbs": [] - }, - { - "name": "pods/log", - "singularName": "", - "namespaced": true, - "kind": "Pod", - "verbs": [ - "get" - ] - }, - { - "name": "pods/portforward", - "singularName": "", - "namespaced": true, - "kind": "Pod", - "verbs": [] - }, - { - "name": "pods/proxy", - "singularName": "", - "namespaced": true, - "kind": "Pod", - "verbs": [] - }, - { - "name": "pods/status", - "singularName": "", - "namespaced": true, - "kind": "Pod", - "verbs": [ - "get", - "patch", - "update" - ] - }, - { - "name": "podtemplates", - "singularName": "", - "namespaced": true, - "kind": "PodTemplate", - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update", - "watch" - ] - }, - { - "name": "replicationcontrollers", - "singularName": "", - "namespaced": true, - "kind": "ReplicationController", - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update", - "watch" - ], - "shortNames": [ - "rc" - ], - "categories": [ - "all" - ] - }, - { - "name": "replicationcontrollers/scale", - "singularName": "", - "namespaced": true, - "group": "autoscaling", - "version": "v1", - "kind": "Scale", - "verbs": [ - "get", - "patch", - "update" - ] - }, - { - "name": "replicationcontrollers/status", - "singularName": "", - "namespaced": true, - "kind": "ReplicationController", - "verbs": [ - "get", - "patch", - "update" - ] - }, - { - "name": "resourcequotas", - "singularName": "", - "namespaced": true, - "kind": "ResourceQuota", - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update", - "watch" - ], - "shortNames": [ - "quota" - ] - }, - { - "name": "resourcequotas/status", - "singularName": "", - "namespaced": true, - "kind": "ResourceQuota", - "verbs": [ - "get", - "patch", - "update" - ] - }, - { - "name": "secrets", - "singularName": "", - "namespaced": true, - "kind": "Secret", - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update", - "watch" - ] - }, - { - "name": "serviceaccounts", - "singularName": "", - "namespaced": true, - "kind": "ServiceAccount", - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update", - "watch" - ], - "shortNames": [ - "sa" - ] - }, - { - "name": "services", - "singularName": "", - "namespaced": true, - "kind": "Service", - "verbs": [ - "create", - "delete", - "get", - "list", - "patch", - "update", - "watch" - ], - "shortNames": [ - "svc" - ], - "categories": [ - "all" - ] - }, - { - "name": "services/proxy", - "singularName": "", - "namespaced": true, - "kind": "Service", - "verbs": [] - }, - { - "name": "services/status", - "singularName": "", - "namespaced": true, - "kind": "Service", - "verbs": [ - "get", - "patch", - "update" - ] - } - ] -} \ No newline at end of file diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/api.json b/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/api.json deleted file mode 100644 index f266b12ec3..0000000000 --- a/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/api.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "kind": "APIVersions", - "versions": [ - "v1" - ], - "serverAddressByClientCIDRs": [ - { - "clientCIDR": "0.0.0.0/0", - "serverAddress": "localhost:8880" - } - ] -} \ No newline at end of file diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/apis-response.json b/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/apis-response.json deleted file mode 100644 index 2dacc20d1b..0000000000 --- a/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/apis-response.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "kind": "APIGroupList", - "apiVersion": "v1", - "groups": [ - { - "name": "route.openshift.io", - "versions": [ - { - "groupVersion": "route.openshift.io/v1", - "version": "v1" - } - ], - "preferredVersion": { - "groupVersion": "route.openshift.io/v1", - "version": "v1" - }, - "serverAddressByClientCIDRs": null - } - ] -} \ No newline at end of file diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/apis-route-v1.json b/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/apis-route-v1.json deleted file mode 100644 index 5efef9a65c..0000000000 --- a/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/apis-route-v1.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "kind": "APIResourceList", - "apiVersion": "v1", - "groupVersion": "route.openshift.io/v1", - "resources": [ - { - "name": "routes", - "singularName": "", - "namespaced": true, - "kind": "Route", - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update", - "watch" - ], - "categories": [ - "all" - ] - }, - { - "name": "routes/status", - "singularName": "", - "namespaced": true, - "kind": "Route", - "verbs": [ - "get", - "patch", - "update" - ] - } - ] -} \ No newline at end of file diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/namespace-default.json b/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/namespace-default.json deleted file mode 100644 index 2f81fcf09c..0000000000 --- a/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/namespace-default.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "kind": "Namespace", - "apiVersion": "v1", - "metadata": { - "name": "default", - "selfLink": "/api/v1/namespaces/default", - "uid": "cb37acb7-d084-11e8-aea9-5254001e7d16", - "resourceVersion": "977", - "creationTimestamp": "2018-10-15T14:15:39Z", - "annotations": { - "openshift.io/sa.scc.mcs": "s0:c1,c0", - "openshift.io/sa.scc.supplemental-groups": "1000000000/10000", - "openshift.io/sa.scc.uid-range": "1000000000/10000" - } - }, - "spec": { - "finalizers": [ - "kubernetes", - "openshift.io/origin" - ] - }, - "status": { - "phase": "Active" - } -} \ No newline at end of file diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/oapi-response.json b/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/oapi-response.json deleted file mode 100644 index f802005ab9..0000000000 --- a/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/oapi-response.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "kind": "APIVersions", - "versions": [ - "v1" - ], - "serverAddressByClientCIDRs": [ - { - "clientCIDR": "0.0.0.0/0", - "serverAddress": "192.168.121.194:8443" - } - ] -} \ No newline at end of file diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/oapi-v1.json b/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/oapi-v1.json deleted file mode 100644 index 6f5e16a6b9..0000000000 --- a/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/oapi-v1.json +++ /dev/null @@ -1,732 +0,0 @@ -{ - "kind": "APIResourceList", - "groupVersion": "v1", - "resources": [ - { - "name": "appliedclusterresourcequotas", - "singularName": "", - "namespaced": true, - "kind": "AppliedClusterResourceQuota", - "verbs": [ - "get", - "list" - ] - }, - { - "name": "buildconfigs", - "singularName": "", - "namespaced": true, - "kind": "BuildConfig", - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update", - "watch" - ], - "shortNames": [ - "bc" - ] - }, - { - "name": "buildconfigs/instantiate", - "singularName": "", - "namespaced": true, - "kind": "BuildRequest", - "verbs": [ - "create" - ] - }, - { - "name": "buildconfigs/instantiatebinary", - "singularName": "", - "namespaced": true, - "kind": "BinaryBuildRequestOptions", - "verbs": [] - }, - { - "name": "buildconfigs/webhooks", - "singularName": "", - "namespaced": true, - "kind": "Build", - "verbs": [] - }, - { - "name": "builds", - "singularName": "", - "namespaced": true, - "kind": "Build", - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update", - "watch" - ] - }, - { - "name": "builds/clone", - "singularName": "", - "namespaced": true, - "kind": "BuildRequest", - "verbs": [ - "create" - ] - }, - { - "name": "builds/details", - "singularName": "", - "namespaced": true, - "kind": "Build", - "verbs": [ - "update" - ] - }, - { - "name": "builds/log", - "singularName": "", - "namespaced": true, - "kind": "BuildLog", - "verbs": [ - "get" - ] - }, - { - "name": "clusternetworks", - "singularName": "", - "namespaced": false, - "kind": "ClusterNetwork", - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update", - "watch" - ] - }, - { - "name": "clusterresourcequotas", - "singularName": "", - "namespaced": false, - "kind": "ClusterResourceQuota", - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update", - "watch" - ], - "shortNames": [ - "clusterquota" - ] - }, - { - "name": "clusterresourcequotas/status", - "singularName": "", - "namespaced": false, - "kind": "ClusterResourceQuota", - "verbs": [ - "get", - "patch", - "update" - ] - }, - { - "name": "clusterrolebindings", - "singularName": "", - "namespaced": false, - "kind": "ClusterRoleBinding", - "verbs": [ - "create", - "delete", - "get", - "list", - "patch", - "update" - ] - }, - { - "name": "clusterroles", - "singularName": "", - "namespaced": false, - "kind": "ClusterRole", - "verbs": [ - "create", - "delete", - "get", - "list", - "patch", - "update" - ] - }, - { - "name": "deploymentconfigs", - "singularName": "", - "namespaced": true, - "kind": "DeploymentConfig", - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update", - "watch" - ], - "shortNames": [ - "dc" - ] - }, - { - "name": "deploymentconfigs/instantiate", - "singularName": "", - "namespaced": true, - "kind": "DeploymentRequest", - "verbs": [ - "create" - ] - }, - { - "name": "deploymentconfigs/log", - "singularName": "", - "namespaced": true, - "kind": "DeploymentLog", - "verbs": [ - "get" - ] - }, - { - "name": "deploymentconfigs/rollback", - "singularName": "", - "namespaced": true, - "kind": "DeploymentConfigRollback", - "verbs": [ - "create" - ] - }, - { - "name": "deploymentconfigs/scale", - "singularName": "", - "namespaced": true, - "group": "extensions", - "version": "v1beta1", - "kind": "Scale", - "verbs": [ - "get", - "patch", - "update" - ] - }, - { - "name": "deploymentconfigs/status", - "singularName": "", - "namespaced": true, - "kind": "DeploymentConfig", - "verbs": [ - "get", - "patch", - "update" - ] - }, - { - "name": "egressnetworkpolicies", - "singularName": "", - "namespaced": true, - "kind": "EgressNetworkPolicy", - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update", - "watch" - ] - }, - { - "name": "groups", - "singularName": "", - "namespaced": false, - "kind": "Group", - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update", - "watch" - ] - }, - { - "name": "hostsubnets", - "singularName": "", - "namespaced": false, - "kind": "HostSubnet", - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update", - "watch" - ] - }, - { - "name": "identities", - "singularName": "", - "namespaced": false, - "kind": "Identity", - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update", - "watch" - ] - }, - { - "name": "images", - "singularName": "", - "namespaced": false, - "kind": "Image", - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update", - "watch" - ] - }, - { - "name": "imagesignatures", - "singularName": "", - "namespaced": false, - "kind": "ImageSignature", - "verbs": [ - "create", - "delete" - ] - }, - { - "name": "imagestreamimages", - "singularName": "", - "namespaced": true, - "kind": "ImageStreamImage", - "verbs": [ - "get" - ], - "shortNames": [ - "isimage" - ] - }, - { - "name": "imagestreamimports", - "singularName": "", - "namespaced": true, - "kind": "ImageStreamImport", - "verbs": [ - "create" - ] - }, - { - "name": "imagestreammappings", - "singularName": "", - "namespaced": true, - "kind": "ImageStreamMapping", - "verbs": [ - "create" - ] - }, - { - "name": "imagestreams", - "singularName": "", - "namespaced": true, - "kind": "ImageStream", - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update", - "watch" - ], - "shortNames": [ - "is" - ] - }, - { - "name": "imagestreams/secrets", - "singularName": "", - "namespaced": true, - "kind": "SecretList", - "verbs": [ - "get" - ] - }, - { - "name": "imagestreams/status", - "singularName": "", - "namespaced": true, - "kind": "ImageStream", - "verbs": [ - "get", - "patch", - "update" - ] - }, - { - "name": "imagestreamtags", - "singularName": "", - "namespaced": true, - "kind": "ImageStreamTag", - "verbs": [ - "create", - "delete", - "get", - "list", - "patch", - "update" - ], - "shortNames": [ - "istag" - ] - }, - { - "name": "localresourceaccessreviews", - "singularName": "", - "namespaced": true, - "kind": "LocalResourceAccessReview", - "verbs": [ - "create" - ] - }, - { - "name": "localsubjectaccessreviews", - "singularName": "", - "namespaced": true, - "kind": "LocalSubjectAccessReview", - "verbs": [ - "create" - ] - }, - { - "name": "netnamespaces", - "singularName": "", - "namespaced": false, - "kind": "NetNamespace", - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update", - "watch" - ] - }, - { - "name": "oauthaccesstokens", - "singularName": "", - "namespaced": false, - "kind": "OAuthAccessToken", - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update", - "watch" - ] - }, - { - "name": "oauthauthorizetokens", - "singularName": "", - "namespaced": false, - "kind": "OAuthAuthorizeToken", - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update", - "watch" - ] - }, - { - "name": "oauthclientauthorizations", - "singularName": "", - "namespaced": false, - "kind": "OAuthClientAuthorization", - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update", - "watch" - ] - }, - { - "name": "oauthclients", - "singularName": "", - "namespaced": false, - "kind": "OAuthClient", - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update", - "watch" - ] - }, - { - "name": "podsecuritypolicyreviews", - "singularName": "", - "namespaced": true, - "kind": "PodSecurityPolicyReview", - "verbs": [ - "create" - ] - }, - { - "name": "podsecuritypolicyselfsubjectreviews", - "singularName": "", - "namespaced": true, - "kind": "PodSecurityPolicySelfSubjectReview", - "verbs": [ - "create" - ] - }, - { - "name": "podsecuritypolicysubjectreviews", - "singularName": "", - "namespaced": true, - "kind": "PodSecurityPolicySubjectReview", - "verbs": [ - "create" - ] - }, - { - "name": "processedtemplates", - "singularName": "", - "namespaced": true, - "kind": "Template", - "verbs": [ - "create" - ] - }, - { - "name": "projectrequests", - "singularName": "", - "namespaced": false, - "kind": "ProjectRequest", - "verbs": [ - "create", - "list" - ] - }, - { - "name": "projects", - "singularName": "", - "namespaced": false, - "kind": "Project", - "verbs": [ - "create", - "delete", - "get", - "list", - "patch", - "update", - "watch" - ] - }, - { - "name": "resourceaccessreviews", - "singularName": "", - "namespaced": true, - "kind": "ResourceAccessReview", - "verbs": [ - "create" - ] - }, - { - "name": "rolebindingrestrictions", - "singularName": "", - "namespaced": true, - "kind": "RoleBindingRestriction", - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update", - "watch" - ] - }, - { - "name": "rolebindings", - "singularName": "", - "namespaced": true, - "kind": "RoleBinding", - "verbs": [ - "create", - "delete", - "get", - "list", - "patch", - "update" - ] - }, - { - "name": "roles", - "singularName": "", - "namespaced": true, - "kind": "Role", - "verbs": [ - "create", - "delete", - "get", - "list", - "patch", - "update" - ] - }, - { - "name": "routes", - "singularName": "", - "namespaced": true, - "kind": "Route", - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update", - "watch" - ] - }, - { - "name": "routes/status", - "singularName": "", - "namespaced": true, - "kind": "Route", - "verbs": [ - "get", - "patch", - "update" - ] - }, - { - "name": "selfsubjectrulesreviews", - "singularName": "", - "namespaced": true, - "kind": "SelfSubjectRulesReview", - "verbs": [ - "create" - ] - }, - { - "name": "subjectaccessreviews", - "singularName": "", - "namespaced": true, - "kind": "SubjectAccessReview", - "verbs": [ - "create" - ] - }, - { - "name": "subjectrulesreviews", - "singularName": "", - "namespaced": true, - "kind": "SubjectRulesReview", - "verbs": [ - "create" - ] - }, - { - "name": "templates", - "singularName": "", - "namespaced": true, - "kind": "Template", - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update", - "watch" - ] - }, - { - "name": "useridentitymappings", - "singularName": "", - "namespaced": false, - "kind": "UserIdentityMapping", - "verbs": [ - "create", - "delete", - "get", - "patch", - "update" - ] - }, - { - "name": "users", - "singularName": "", - "namespaced": false, - "kind": "User", - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update", - "watch" - ] - } - ] -} \ No newline at end of file diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/openshift-version.json b/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/openshift-version.json deleted file mode 100644 index 374e2e7dca..0000000000 --- a/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/openshift-version.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "major": "3", - "minor": "10+", - "gitVersion": "v3.10.0+2084755-68", - "gitCommit": "2084755", - "gitTreeState": "", - "buildDate": "2018-10-30T09:01:17Z", - "goVersion": "", - "compiler": "", - "platform": "" -} \ No newline at end of file diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/route-response.json b/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/route-response.json deleted file mode 100644 index 8e0bdd30c2..0000000000 --- a/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/route-response.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "kind": "Route", - "apiVersion": "v1", - "metadata": { - "name": "proxy", - "namespace": "default", - "selfLink": "/oapi/v1/namespaces/default/routes/proxy", - "uid": "3bf12cd8-d14a-11e8-82c2-5254001e7d16", - "resourceVersion": "45934", - "creationTimestamp": "2018-10-16T13:48:59Z", - "annotations": { - "openshift.io/host.generated": "true" - } - }, - "spec": { - "host": "127.0.0.1", - "to": { - "kind": "Service", - "name": "proxy", - "weight": 100 - }, - "wildcardPolicy": "None" - }, - "status": { - "ingress": [ - { - "host": "127.0.0.1", - "routerName": "router", - "conditions": [ - { - "type": "Admitted", - "status": "True", - "lastTransitionTime": "2018-10-16T13:49:00Z" - } - ], - "wildcardPolicy": "None" - } - ] - } -} \ No newline at end of file diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/sa-oauth-redirect-reference.json b/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/sa-oauth-redirect-reference.json deleted file mode 100644 index 56a52c49b5..0000000000 --- a/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/sa-oauth-redirect-reference.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "kind": "ServiceAccount", - "apiVersion": "v1", - "metadata": { - "name": "proxy-with-redirect-reference", - "namespace": "default", - "selfLink": "/api/v1/namespaces/default/serviceaccounts/proxy", - "uid": "3befc25c-d14a-11e8-8666-5254001e7d16", - "resourceVersion": "205225", - "creationTimestamp": "2018-10-16T13: 48:59Z", - "annotations": { - "serviceaccounts.openshift.io/oauth-redirectreference.primary": "{\"kind\":\"OAuthRedirectReference\",\"apiVersion\":\"v1\",\"reference\":{\"kind\":\"Route\",\"name\":\"proxy\"}}" - } - } -} \ No newline at end of file diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/sa-oauth-redirect-uri.json b/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/sa-oauth-redirect-uri.json deleted file mode 100644 index afc9b8f601..0000000000 --- a/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/sa-oauth-redirect-uri.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "kind": "ServiceAccount", - "apiVersion": "v1", - "metadata": { - "name": "proxy-with-redirect-uri", - "namespace": "default", - "selfLink": "/api/v1/namespaces/default/serviceaccounts/proxy", - "uid": "3befc25c-d14a-11e8-8666-5254001e7d16", - "resourceVersion": "205225", - "creationTimestamp": "2018-10-16T13: 48:59Z", - "annotations": { - "serviceaccounts.openshift.io/oauth-redirecturi.first": "http://localhost:8180/auth/realms/master/app/auth", - "serviceaccounts.openshift.io/oauth-redirecturi.second": "http://localhost:8180/auth/realms/master/app/auth/second", - "serviceaccounts.openshift.io/oauth-redirecturi.third": "http://localhost:8180/auth/realms/master/app/auth/third" - } - } -} \ No newline at end of file diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/sa-system.json b/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/sa-system.json deleted file mode 100644 index e118fd7ff3..0000000000 --- a/testsuite/integration-arquillian/tests/base/src/test/resources/openshift/client-storage/sa-system.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "kind": "ServiceAccount", - "apiVersion": "v1", - "metadata": { - "name": "system", - "namespace": "default", - "selfLink": "/api/v1/namespaces/default/serviceaccounts/proxy", - "uid": "3befc25c-d14a-11e8-8666-5254001e7d16", - "resourceVersion": "205225", - "creationTimestamp": "2018-10-16T13: 48:59Z" - } -} \ No newline at end of file diff --git a/testsuite/integration-arquillian/tests/base/testsuites/base-suite b/testsuite/integration-arquillian/tests/base/testsuites/base-suite index 60e8dfdfa8..34258ebdb2 100644 --- a/testsuite/integration-arquillian/tests/base/testsuites/base-suite +++ b/testsuite/integration-arquillian/tests/base/testsuites/base-suite @@ -28,7 +28,6 @@ migration,4 model,6 oauth,6 oidc,6 -openshift,6 policy,6 providers,4 runonserver,6