KEYCLOAK-10898 WildFly Adapter CLI based installation scripts
This commit is contained in:
parent
8061aa5217
commit
7c91e36e43
7 changed files with 341 additions and 6 deletions
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* Copyright 2020 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.oidc.installation;
|
||||
|
||||
import static org.keycloak.protocol.util.ClientCliInstallationUtil.quote;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.protocol.ClientInstallationProvider;
|
||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
|
||||
public class KeycloakOIDCJbossSubsystemClientCliInstallation implements ClientInstallationProvider {
|
||||
|
||||
@Override
|
||||
public Response generateInstallation(KeycloakSession session, RealmModel realm, ClientModel client, URI baseUri) {
|
||||
String deploymentName = "WAR MODULE NAME.war";
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
builder
|
||||
.append("/subsystem=keycloak/secure-deployment=").append(quote(deploymentName)).append("/:add( \\\n")
|
||||
.append(" realm=").append(quote(realm.getName())).append(", \\\n")
|
||||
.append(" resource=").append(quote(client.getClientId())).append(", \\\n")
|
||||
.append(" auth-server-url=").append(baseUri).append(", \\\n");
|
||||
|
||||
if (client.isBearerOnly()){
|
||||
builder.append(" bearer-only=true, \\\n");
|
||||
} else if (client.isPublicClient()) {
|
||||
builder.append(" public-client=true, \\\n");
|
||||
}
|
||||
|
||||
if (KeycloakOIDCClientInstallation.showVerifyTokenAudience(client)) {
|
||||
builder.append(" verify-token-audience=true, \\\n");
|
||||
}
|
||||
if (client.getRoles().size() > 0) {
|
||||
builder.append(" use-resource-role-mappings=true, \\\n");
|
||||
}
|
||||
builder.append(" ssl-required=").append(realm.getSslRequired().name()).append(")\n\n");
|
||||
|
||||
|
||||
if (KeycloakOIDCClientInstallation.showClientCredentialsAdapterConfig(client)) {
|
||||
Map<String, Object> adapterConfig = KeycloakOIDCClientInstallation.getClientCredentialsAdapterConfig(session, client);
|
||||
for (Map.Entry<String, Object> entry : adapterConfig.entrySet()) {
|
||||
builder.append("/subsystem=keycloak/secure-deployment=").append(quote(deploymentName)).append("/")
|
||||
.append("credential=").append(entry.getKey()).append(":add(value=").append(entry.getValue())
|
||||
.append(")\n");
|
||||
}
|
||||
}
|
||||
return Response.ok(builder.toString(), MediaType.TEXT_PLAIN_TYPE).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProtocol() {
|
||||
return OIDCLoginProtocol.LOGIN_PROTOCOL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayType() {
|
||||
return "Keycloak OIDC JBoss Subsystem CLI";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHelpText() {
|
||||
return "CLI script you must edit and apply to your client app server. This type of configuration is useful when you can't or don't want to crack open your WAR file.";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientInstallationProvider create(KeycloakSession session) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postInit(KeycloakSessionFactory factory) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "keycloak-oidc-jboss-subsystem-cli";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDownloadOnly() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFilename() {
|
||||
return "keycloak-oidc-subsystem.cli";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMediaType() {
|
||||
return MediaType.TEXT_PLAIN;
|
||||
}
|
||||
}
|
|
@ -49,7 +49,7 @@ public class KeycloakSamlClientInstallation implements ClientInstallationProvide
|
|||
}
|
||||
|
||||
public static void baseXml(KeycloakSession session, RealmModel realm, ClientModel client, URI baseUri, SamlClient samlClient, StringBuilder buffer) {
|
||||
buffer.append(" <SP entityID=\"").append(client.getClientId()).append("\"\n");
|
||||
buffer.append(" <SP entityID=\"").append(client.getBaseUrl() == null ? "SPECIFY YOUR entityID!" : client.getBaseUrl()).append("\"\n");
|
||||
buffer.append(" sslPolicy=\"").append(realm.getSslRequired().name()).append("\"\n");
|
||||
buffer.append(" logoutPage=\"SPECIFY YOUR LOGOUT PAGE!\">\n");
|
||||
if (samlClient.requiresClientSignature() || samlClient.requiresEncryption()) {
|
||||
|
@ -128,7 +128,7 @@ public class KeycloakSamlClientInstallation implements ClientInstallationProvide
|
|||
|
||||
@Override
|
||||
public String getHelpText() {
|
||||
return "Keycloak SAML adapter configuration file. Put this in WEB-INF directory of your WAR.";
|
||||
return "Keycloak SAML adapter configuration file you must edit. Put this in WEB-INF directory of your WAR.";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
* Copyright 2020 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.saml.installation;
|
||||
|
||||
import static org.keycloak.protocol.util.ClientCliInstallationUtil.quote;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.protocol.ClientInstallationProvider;
|
||||
import org.keycloak.protocol.saml.SamlClient;
|
||||
import org.keycloak.protocol.saml.SamlProtocol;
|
||||
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.net.URI;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
import org.keycloak.services.resources.RealmsResource;
|
||||
|
||||
public class KeycloakSamlSubsystemCliInstallation implements ClientInstallationProvider {
|
||||
|
||||
@Override
|
||||
public Response generateInstallation(KeycloakSession session, RealmModel realm, ClientModel client, URI baseUri) {
|
||||
SamlClient samlClient = new SamlClient(client);
|
||||
StringBuilder builder = new StringBuilder();
|
||||
String entityId = client.getBaseUrl() == null ? "SPECIFY YOUR entityID!" : client.getBaseUrl();
|
||||
String bindingUrl = RealmsResource.protocolUrl(UriBuilder.fromUri(baseUri))
|
||||
.build(realm.getName(), SamlProtocol.LOGIN_PROTOCOL).toString();
|
||||
|
||||
builder.append("/subsystem=keycloak-saml/secure-deployment=YOUR-WAR.war/:add\n\n")
|
||||
.append("/subsystem=keycloak-saml/secure-deployment=YOUR-WAR.war/SP=")
|
||||
.append(quote(entityId))
|
||||
.append("/:add(sslPolicy=")
|
||||
.append(realm.getSslRequired().name())
|
||||
.append(",logoutPage=")
|
||||
.append(quote("SPECIFY YOUR LOGOUT PAGE!"))
|
||||
.append("\n\n");
|
||||
if (samlClient.requiresClientSignature()) {
|
||||
builder.append("/subsystem=keycloak-saml/secure-deployment=YOUR-WAR.war/SP=")
|
||||
.append(quote(entityId))
|
||||
.append("/Key=KEY1:add(signing=true, \\\nPrivateKeyPem=")
|
||||
.append(quote(samlClient.getClientSigningPrivateKey() == null ? "PRIVATE KEY NOT SET UP OR KNOWN" : samlClient.getClientSigningPrivateKey()))
|
||||
.append(", \\\nCertificatePem=")
|
||||
.append(quote(samlClient.getClientSigningCertificate() == null ? "YOU MUST CONFIGURE YOUR_CLIENT's SIGNING CERTIFICATE" : samlClient.getClientSigningCertificate()))
|
||||
.append(")\n\n");
|
||||
}
|
||||
if (samlClient.requiresEncryption()) {
|
||||
builder.append("/subsystem=keycloak-saml/secure-deployment=YOUR-WAR.war/SP=")
|
||||
.append(quote(entityId))
|
||||
.append("/Key=KEY2:add(encryption=true,PrivateKeyPem=")
|
||||
.append(quote(samlClient.getClientEncryptingPrivateKey() == null ? "PRIVATE KEY NOT SET UP OR KNOWN" : samlClient.getClientEncryptingPrivateKey()))
|
||||
.append(")\n\n");
|
||||
}
|
||||
|
||||
builder.append("/subsystem=keycloak-saml/secure-deployment=YOUR-WAR.war/SP=")
|
||||
.append(quote(entityId))
|
||||
.append("/IDP=idp/:add( \\\n SingleSignOnService={ \\\n signRequest=")
|
||||
.append(Boolean.toString(samlClient.requiresClientSignature()))
|
||||
.append(", \\\n validateResponseSignature=")
|
||||
.append(Boolean.toString(samlClient.requiresRealmSignature()))
|
||||
.append(", \\\n validateAssertionSignature=")
|
||||
.append(Boolean.toString(samlClient.requiresAssertionSignature()))
|
||||
.append(", \\\n requestBinding=POST, \\\n bindingUrl=")
|
||||
.append(bindingUrl)
|
||||
.append("}, \\\n SingleLogoutService={ \\\n signRequest=")
|
||||
.append(Boolean.toString(samlClient.requiresClientSignature()))
|
||||
.append(", \\\n signResponse=")
|
||||
.append(Boolean.toString(samlClient.requiresClientSignature()))
|
||||
.append(", \\\n validateRequestSignature=")
|
||||
.append(Boolean.toString(samlClient.requiresRealmSignature()))
|
||||
.append(", \\\n validateResponseSignature=")
|
||||
.append(Boolean.toString(samlClient.requiresRealmSignature()))
|
||||
.append(", \\\n requestBinding=POST, \\\n responseBinding=POST, \\\n postBindingUrl=")
|
||||
.append(bindingUrl)
|
||||
.append(", \\\n redirectBindingUrl=")
|
||||
.append(bindingUrl)
|
||||
.append("} \\\n)\n\n");
|
||||
|
||||
if (samlClient.requiresClientSignature()) {
|
||||
builder.append("/subsystem=keycloak-saml/secure-deployment=YOUR-WAR.war/SP=")
|
||||
.append(quote(entityId))
|
||||
.append("/IDP=idp/:write-attribute(name=signatureAlgorithm,value=")
|
||||
.append(samlClient.getSignatureAlgorithm())
|
||||
.append(")\n\n");
|
||||
if (samlClient.getCanonicalizationMethod() != null) {
|
||||
builder.append("/subsystem=keycloak-saml/secure-deployment=YOUR-WAR.war/SP=")
|
||||
.append(quote(entityId))
|
||||
.append("/IDP=idp/:write-attribute(name=signatureCanonicalizationMethod,value=")
|
||||
.append(samlClient.getCanonicalizationMethod())
|
||||
.append(")\n");
|
||||
}
|
||||
}
|
||||
|
||||
return Response.ok(builder.toString(), MediaType.TEXT_PLAIN_TYPE).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProtocol() {
|
||||
return SamlProtocol.LOGIN_PROTOCOL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayType() {
|
||||
return "Keycloak SAML JBoss Subsystem CLI";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHelpText() {
|
||||
return "CLI script you must edit and apply to your client app server. This type of configuration is useful when you can't or don't want to crack open your WAR file.";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFilename() {
|
||||
return "keycloak-saml-subsystem.cli";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMediaType() {
|
||||
return MediaType.TEXT_PLAIN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDownloadOnly() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientInstallationProvider create(KeycloakSession session) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postInit(KeycloakSessionFactory factory) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "keycloak-saml-subsystem-cli";
|
||||
}
|
||||
}
|
|
@ -53,12 +53,12 @@ public class KeycloakSamlSubsystemInstallation implements ClientInstallationProv
|
|||
|
||||
@Override
|
||||
public String getDisplayType() {
|
||||
return "Keycloak SAML Wildfly/JBoss Subsystem";
|
||||
return "Keycloak SAML JBoss Subsystem XML";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHelpText() {
|
||||
return "Keycloak SAML adapter Wildfly/JBoss subsystem xml. Put this <subsystem xmlns=\"urn:jboss:domain:keycloak-saml:1.2\"> element of your standalone.xml file.";
|
||||
return "Keycloak SAML adapter JBoss subsystem xml you must edit. Put this into <subsystem xmlns=\"urn:jboss:domain:keycloak-saml:1.2\"> element of your standalone.xml file.";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright 2020 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.util;
|
||||
|
||||
public class ClientCliInstallationUtil {
|
||||
public static String quote(String value) {
|
||||
return "\"" + value.replaceAll("\\\\", "\\\\\\\\").replaceAll("\"", "\\\\\"") + "\"";
|
||||
}
|
||||
}
|
|
@ -16,10 +16,12 @@
|
|||
#
|
||||
|
||||
org.keycloak.protocol.oidc.installation.KeycloakOIDCClientInstallation
|
||||
org.keycloak.protocol.oidc.installation.KeycloakOIDCJbossSubsystemClientCliInstallation
|
||||
org.keycloak.protocol.oidc.installation.KeycloakOIDCJbossSubsystemClientInstallation
|
||||
org.keycloak.protocol.saml.installation.KeycloakSamlClientInstallation
|
||||
org.keycloak.protocol.saml.installation.SamlSPDescriptorClientInstallation
|
||||
org.keycloak.protocol.saml.installation.ModAuthMellonClientInstallation
|
||||
org.keycloak.protocol.saml.installation.KeycloakSamlSubsystemCliInstallation
|
||||
org.keycloak.protocol.saml.installation.KeycloakSamlSubsystemInstallation
|
||||
org.keycloak.protocol.docker.installation.DockerVariableOverrideInstallationProvider
|
||||
org.keycloak.protocol.docker.installation.DockerRegistryConfigFileInstallationProvider
|
||||
|
|
|
@ -109,6 +109,13 @@ public class InstallationTest extends AbstractClientTest {
|
|||
assertOidcInstallationConfig(json);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOidcJBossCli() {
|
||||
String cli = oidcClient.getInstallationProvider("keycloak-oidc-jboss-subsystem-cli");
|
||||
assertOidcInstallationConfig(cli);
|
||||
assertThat(cli, containsString("/subsystem=keycloak/secure-deployment=\"WAR MODULE NAME.war\""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOidcBearerOnlyJson() {
|
||||
String json = oidcBearerOnlyClient.getInstallationProvider("keycloak-oidc-keycloak-json");
|
||||
|
@ -167,11 +174,20 @@ public class InstallationTest extends AbstractClientTest {
|
|||
public void testSamlAdapterXml() {
|
||||
String xml = samlClient.getInstallationProvider("keycloak-saml");
|
||||
assertThat(xml, containsString("<keycloak-saml-adapter>"));
|
||||
assertThat(xml, containsString(SAML_NAME));
|
||||
assertThat(xml, containsString("SPECIFY YOUR entityID!"));
|
||||
assertThat(xml, not(containsString(ApiUtil.findActiveKey(testRealmResource()).getCertificate())));
|
||||
assertThat(xml, containsString(samlUrl()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSamlAdapterCli() {
|
||||
String cli = samlClient.getInstallationProvider("keycloak-saml-subsystem-cli");
|
||||
assertThat(cli, containsString("/subsystem=keycloak-saml/secure-deployment=YOUR-WAR.war/"));
|
||||
assertThat(cli, containsString("SPECIFY YOUR entityID!"));
|
||||
assertThat(cli, not(containsString(ApiUtil.findActiveKey(testRealmResource()).getCertificate())));
|
||||
assertThat(cli, containsString(samlUrl()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSamlMetadataSpDescriptor() {
|
||||
String xml = samlClient.getInstallationProvider(SamlSPDescriptorClientInstallation.SAML_CLIENT_INSTALATION_SP_DESCRIPTOR);
|
||||
|
@ -184,7 +200,7 @@ public class InstallationTest extends AbstractClientTest {
|
|||
public void testSamlJBossXml() {
|
||||
String xml = samlClient.getInstallationProvider("keycloak-saml-subsystem");
|
||||
assertThat(xml, containsString("<secure-deployment"));
|
||||
assertThat(xml, containsString(SAML_NAME));
|
||||
assertThat(xml, containsString("SPECIFY YOUR entityID!"));
|
||||
assertThat(xml, not(containsString(ApiUtil.findActiveKey(testRealmResource()).getCertificate())));
|
||||
assertThat(xml, containsString(samlUrl()));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue