diff --git a/README.md b/README.md index 235aa86..800fc8e 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ The plugin allows user to login in GoCD using an Keycloak account. It is implemented using [GoCD authorization endpoint](https://plugin-api.gocd.org/current/authorization/). +Starting with release 1.1.0, this plugin will work by default with Keycloak >= 17.0.0 and GOCD >= 20.3.0 + # Installation Installation documentation available [here](docs/INSTALL.md). @@ -15,6 +17,7 @@ Installation documentation available [here](docs/INSTALL.md). To build the jar, run `./gradlew clean test assemble` ### Information about this plugin + This plugin was created based on [okta-oauth-authorization-plugin](https://github.com/szamfirov/gocd-okta-oauth-authorization-plugin) ## License diff --git a/build.gradle b/build.gradle index 8f7bf29..2cd21d1 100644 --- a/build.gradle +++ b/build.gradle @@ -18,7 +18,7 @@ apply plugin: 'java' apply from: 'plugin-common.gradle' -project.ext.pluginVersion = '1.0.3' +project.ext.pluginVersion = '2.0.0' project.ext.fullVersion = project.distVersion ? "${project.pluginVersion}-${project.distVersion}" : project.pluginVersion version = project.fullVersion @@ -27,7 +27,7 @@ group = 'cd.go' project.ext.pluginDesc = [ id : 'cd.go.authorization.keycloak', version : project.fullVersion, - goCdVersion: '17.5.0', + goCdVersion: '23.3.0', name : 'Keycloak oauth authorization plugin', description: 'Keycloak oauth authorization plugin for GoCD', vendorName : 'klinux', @@ -40,11 +40,11 @@ repositories { } dependencies { - compileOnly group: 'cd.go.plugin', name: 'go-plugin-api', version: '17.5.0' + compileOnly group: 'cd.go.plugin', name: 'go-plugin-api', version: '23.3.0' compile group: 'com.google.code.gson', name: 'gson', version: '2.8.1' compile group: 'com.squareup.okhttp3', name: 'okhttp', version: '3.8.1' - testCompile group: 'cd.go.plugin', name: 'go-plugin-api', version: '17.5.0' + testCompile group: 'cd.go.plugin', name: 'go-plugin-api', version: '23.3.0' testCompile group: 'junit', name: 'junit', version: '4.12' testCompile group: 'org.mockito', name: 'mockito-core', version: '2.2.28' testCompile group: 'org.hamcrest', name: 'hamcrest-library', version: '1.3' diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 162fc06..bab125a 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -2,28 +2,29 @@ ## Requirements -* GoCD server version v17.5.0 or above +* GoCD server version v23.3.0 or above * Keycloak [API documentation](https://www.keycloak.org/docs-api/11.0/rest-api/index.html) ## Installation -Copy the file `build/libs/keycloak-oauth-authorization-plugin-VERSION.jar` to the GoCD server under `${GO_SERVER_DIR}/plugins/external` -and restart the server. The `GO_SERVER_DIR` is usually `/var/lib/go-server` on Linux and `C:\Program Files\Go Server` +Copy the file `build/libs/keycloak-oauth-authorization-plugin-VERSION.jar` to the GoCD server under `${GO_SERVER_DIR}/plugins/external` +and restart the server. The `GO_SERVER_DIR` is usually `/var/lib/go-server` on Linux and `C:\Program Files\Go Server` on Windows. ## Configuration + Provide details of the Keycloak server to connect to via an [Authorization Configuration](AUTHORIZATION_CONFIGURATION.md). -### Configure Keycloak Client +### Configure Keycloak Client 1. Sign in Keycloak Console 2. Select the realm that you want to configure. Ex. **Master** -3. Click in **Clients** menu +3. Click in **Clients** menu 4. Click **Add** button 5. On the form insert the client name 6. On the next page, set this configs: 1. In **Access Type** select **Confidential** - 2. In **Valid Redirect URIs** insert the URL of GoCD, ex.: **http://localhost:8153** + 2. In **Valid Redirect URIs** insert the URL of GoCD, ex.: **** 3. In **Credentials** tab copy value of **Secret** ### Create Group Configuration @@ -37,5 +38,5 @@ Provide details of the Keycloak server to connect to via an [Authorization Confi 4. Select the **user** that you want to configure this role 5. Select **Groups** tab and select the group in **Available Groups** -> Obs.: By default Keycloak do not provide group definition on user session, to get this, edit +> Obs.: By default Keycloak do not provide group definition on user session, to get this, edit >**profile** scope and add groups in **Mappers** tab, thie scope needs to be added as builtin. diff --git a/plugin-common.gradle b/plugin-common.gradle index 9de2013..5c8c618 100644 --- a/plugin-common.gradle +++ b/plugin-common.gradle @@ -37,8 +37,8 @@ def releaseRevision = { -> project.ext.gitRevision = gitRevision() project.ext.distVersion = releaseRevision() -sourceCompatibility = 1.8 -targetCompatibility = 1.8 +sourceCompatibility = 1.11 +targetCompatibility = 1.11 project.ext.color = [ ANSI_BOLD_WHITE: "\u001B[0;1m", diff --git a/src/main/java/cd/go/authorization/keycloak/Constants.java b/src/main/java/cd/go/authorization/keycloak/Constants.java index 1be964a..2d2f08a 100644 --- a/src/main/java/cd/go/authorization/keycloak/Constants.java +++ b/src/main/java/cd/go/authorization/keycloak/Constants.java @@ -25,7 +25,7 @@ public interface Constants { String EXTENSION_TYPE = "authorization"; // The extension point API version that this plugin understands - String API_VERSION = "1.0"; + String API_VERSION = "2.0"; // the identifier of this plugin GoPluginIdentifier PLUGIN_IDENTIFIER = new GoPluginIdentifier(EXTENSION_TYPE, Collections.singletonList(API_VERSION)); diff --git a/src/main/java/cd/go/authorization/keycloak/KeycloakApiClient.java b/src/main/java/cd/go/authorization/keycloak/KeycloakApiClient.java index 0522a98..6ace8b5 100644 --- a/src/main/java/cd/go/authorization/keycloak/KeycloakApiClient.java +++ b/src/main/java/cd/go/authorization/keycloak/KeycloakApiClient.java @@ -60,7 +60,6 @@ public String authorizationServerUrl(String callbackUrl) throws Exception { return HttpUrl.parse(keycloakConfiguration.keycloakEndpoint()) .newBuilder() - .addPathSegments("auth") .addPathSegments("realms") .addPathSegments(realm) .addPathSegments("protocol") @@ -86,7 +85,6 @@ public TokenInfo fetchAccessToken(Map params) throws Exception { final String accessTokenUrl = HttpUrl.parse(keycloakConfiguration.keycloakEndpoint()) .newBuilder() - .addPathSegments("auth") .addPathSegments("realms") .addPathSegments(realm) .addPathSegments("protocol") @@ -118,7 +116,6 @@ public KeycloakUser userProfile(TokenInfo tokenInfo) throws Exception { final String userProfileUrl = HttpUrl.parse(keycloakConfiguration.keycloakEndpoint()) .newBuilder() - .addPathSegments("auth") .addPathSegments("realms") .addPathSegments(realm) .addPathSegments("protocol") diff --git a/src/test/java/cd/go/authorization/keycloak/KeycloakApiClientTest.java b/src/test/java/cd/go/authorization/keycloak/KeycloakApiClientTest.java index 92c8f9f..583e1e1 100644 --- a/src/test/java/cd/go/authorization/keycloak/KeycloakApiClientTest.java +++ b/src/test/java/cd/go/authorization/keycloak/KeycloakApiClientTest.java @@ -73,7 +73,7 @@ public void tearDown() throws Exception { public void shouldReturnAuthorizationServerUrl() throws Exception { final String authorizationServerUrl = KeycloakApiClient.authorizationServerUrl("call-back-url"); - assertThat(authorizationServerUrl, startsWith("https://example.com/auth/realms/master/protocol/openid-connect/auth?client_id=client-id&redirect_uri=call-back-url&response_type=code&scope=openid%20profile%20email%20roles&state=")); + assertThat(authorizationServerUrl, startsWith("https://example.com/realms/master/protocol/openid-connect/auth?client_id=client-id&redirect_uri=call-back-url&response_type=code&scope=openid%20profile%20email%20roles&state=")); } @Test @@ -89,7 +89,7 @@ public void shouldFetchTokenInfoUsingAuthorizationCode() throws Exception { assertThat(tokenInfo.accessToken(), is("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9")); RecordedRequest request = server.takeRequest(); - assertEquals("POST /auth/realms/master/protocol/openid-connect/token HTTP/1.1", request.getRequestLine()); + assertEquals("POST /realms/master/protocol/openid-connect/token HTTP/1.1", request.getRequestLine()); assertEquals("application/x-www-form-urlencoded", request.getHeader("Content-Type")); assertEquals("client_id=client-id&client_secret=client-secret&code=some-code&grant_type=authorization_code&redirect_uri=callback-url", request.getBody().readUtf8()); } @@ -108,7 +108,7 @@ public void shouldFetchUserProfile() throws Exception { assertThat(KeycloakUser.getEmail(), is("foo@bar.com")); RecordedRequest request = server.takeRequest(); - assertEquals("GET /auth/realms/master/protocol/openid-connect/userinfo HTTP/1.1", request.getRequestLine()); + assertEquals("GET /realms/master/protocol/openid-connect/userinfo HTTP/1.1", request.getRequestLine()); assertEquals("Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9", request.getHeader("Authorization")); } @@ -121,7 +121,7 @@ public void shouldErrorOutWhenAPIRequestFails() throws Exception { when(KeycloakConfiguration.keycloakEndpoint()).thenReturn(server.url("/").toString()); thrown.expect(RuntimeException.class); - thrown.expectMessage("Api call to `/auth/realms/master/protocol/openid-connect/userinfo` failed with error: `Unauthorized`"); + thrown.expectMessage("Api call to `/realms/master/protocol/openid-connect/userinfo` failed with error: `Unauthorized`"); KeycloakApiClient.userProfile(tokenInfo); }