diff --git a/README.md b/README.md
index 55b4e15..ec08256 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
## Description
-This plugin enables user authentication and Single Sign-On via OpenShift. It is heavily based on the code by Julien Lancelot. Tested on version 7 of Sonarqube and OCP 3.11. It is intended to run deployed in a pod on OpenShift.
+This plugin enables user authentication and Single Sign-On via OpenShift. It is based on the code by Julien Lancelot. Tested on version 7 of Sonarqube and OCP 3.11. It is intended to run deployed in a pod on OpenShift.
This plugin is designed to work out of the box without configuration. During plugin deployment, it looks up oauth information from OpenShift's well-known information and takes advantage of information already on the running pod.
@@ -16,7 +16,7 @@ During deployment the plugin will:
## Installation
-This plugin is not currently hosted anywhere. So build and place this plugin on to the volume where Sonarqube reads plugins at startup. Typically, this might be `/opt/sonarqube/data/plugins`.
+This plugin is currently hosted at [rht-labs](https://github.com/rht-labs/sonar-auth-openshift/releases/latest). The latest jar is [here](https://github.com/rht-labs/sonar-auth-openshift/releases/latest/download/sonar-auth-openshift-plugin.jar). You can build it locally and place this plugin on to the volume where Sonarqube reads plugins at startup if modifying it. Typically, this might be `/opt/sonarqube/data/plugins`.
The service account can be used as the oauth client in OpenShift. The service account that runs Sonarqube should have a redirect uri that references the route that Sonarqube is using. You must specify this service account in the DeploymentConfig.
@@ -45,13 +45,31 @@ You may also enable it in the Administrative console
## Configuration
-This plugin will map OpenShift roles to Sonarqube roles. These values are set with the property (shown with the default value if property is not set)
+This plugin will map OpenShift groups to Sonarqube roles. These values are set with the property
```
-sonar.auth.openshift.sar.groups=admin=sonar-administrators,edit=sonar-users,view=sonar-users
+sonar.auth.openshift.sar.groups=ocp-admin=sonar-administrators,ocp-users=sonar-users
+```
+
+This shows that Sonarqube will allow OpenShift users who are in the group ocp-admin users to be administrators with the role of sonar-administrators. Ordinary users will be added as sonar-users if they are OpenShift users in the group ocp-users. These OpenShift groups do not exist by default.
+
+The default mapping value is:
+
+```
+sonar.auth.openshift.sar.groups=sonar-administrators=sonar-administrators,sonar-users=sonar-users
+```
+To disable certificate validation (not recommended for production) configure the `ignore.certs` property
+
+```
+ignore.certs=true
+```
+
+The pod that sonarqube runs in should have a valid certificate to access the OpenShift/Kubernetes API. The Oauth server may have a different certificate. That certificate needs to be loaded into the keystore. To do so, place the certificate on the container's file system (via configmap, dockerfile, etc...). Then configure the sonar property to point the location on the file system
+
+```
+oauth.cert=/opt/sonarqube/conf/oauth.crt
```
-The default shown will allow admin users of the project the role of sonar-administrators of Sonarqube. Edit and View role users will be added as sonar-users.
You may choose the background color of the log in button with the property
diff --git a/example/Dockerfile b/example/Dockerfile
index 5bd8f69..5cf9f31 100644
--- a/example/Dockerfile
+++ b/example/Dockerfile
@@ -10,7 +10,7 @@ RUN cp -a /opt/sonarqube/data /opt/sonarqube/data-init && \
chown root:root /opt/sonarqube && chmod -R gu+rwX /opt/sonarqube
ADD plugins.sh /opt/sonarqube/bin/plugins.sh
RUN /opt/sonarqube/bin/plugins.sh $sonar_plugins
-ADD sonar-auth-openshift-plugin-1.0.0.jar /opt/sonarqube/extensions-init/plugins/sonar-auth-openshift-plugin-1.0.0.jar
+ADD sonar-auth-openshift-plugin-1.1.0.jar /opt/sonarqube/extensions-init/plugins/sonar-auth-openshift-plugin-1.1.0.jar
RUN chown root:root /opt/sonarqube -R; \
chmod 6775 /opt/sonarqube -R
USER 1001
diff --git a/example/README.md b/example/README.md
index fe31d96..1bab284 100644
--- a/example/README.md
+++ b/example/README.md
@@ -1,6 +1,5 @@
# Example Build and Deploy
-
```
This example uses ansible. Windows users use a vm or apply each command manually
```
@@ -15,11 +14,13 @@ This section contains an example for how this plugin can be used with Sonarqube
mvn clean package && cp target/sonar-auth-openshift-plugin-1.0.0.jar example/
```
-2. Create a project in OpenShift
-
-```
-oc new-project sonarqube
-```
+2. Inspect the [all.yml](example/inventory/group_vars/all.yml) file. In the following step it will run the [OpenShift Applier](https://github.com/redhat-cop/openshift-applier) to create resources in OpenShift. Most importantly
+ 1. A project / namespace called `sonarqube` that the other resources will belong too.
+ 2. A deployment config to deploy sonarqube with the plugin.
+ 3. A build config to build the sonarqube-auth-openshift project.
+ 4. A route to navigate to the application.
+ 5. Two groups that will define the users and administrators of Sonarqube.
+ 1. Inspect the group allocation. Add/Remove appropriate users for your scenario. Users are listed in the two yaml files located in the files directory. Group creation and editing usually require elvated privileges. Group names are also defined here. If changed, the sonar.properties must also be changed to match.
3. From the example folder run the prerequisites
@@ -27,13 +28,19 @@ oc new-project sonarqube
ansible-galaxy install -r requirements.yml --roles-path=roles
```
-4. From the example folder run the ansible playbook which sets up the build and deploy for Sonarqube including a persistent volume and database
+1. From the example folder, run the ansible playbook which sets up the build and deploy for Sonarqube including a persistent volume and database.
```
ansible-playbook -i inventory/ apply.yml
```
+If the group are already setup and you do not want to add them with this playbook run this command instead
+
+```
+ansible-playbook -i inventory/ apply.yml -e exclude_tags=users_and_groups
+```
+
-5. From the base folder build the Docker container on OpenShift
+1. From the base folder, build the Docker container on OpenShift. This will replace the original build with the build with local files.
```
oc start-build sonarqube --from-dir=. -n sonarqube
diff --git a/example/files/project.yml b/example/files/project.yml
new file mode 100644
index 0000000..f5d4849
--- /dev/null
+++ b/example/files/project.yml
@@ -0,0 +1,9 @@
+apiVersion: project.openshift.io/v1
+kind: Project
+metadata:
+ name: sonarqube
+spec:
+ finalizers:
+ - kubernetes
+status:
+ phase: Active
diff --git a/example/files/sonarqube-admin-group.yml b/example/files/sonarqube-admin-group.yml
new file mode 100644
index 0000000..6195f12
--- /dev/null
+++ b/example/files/sonarqube-admin-group.yml
@@ -0,0 +1,9 @@
+---
+apiVersion: user.openshift.io/v1
+kind: Group
+metadata:
+ name: sonarqube_admin
+users:
+- developer
+- admin1
+- admin2
diff --git a/example/files/sonarqube-user-group.yml b/example/files/sonarqube-user-group.yml
new file mode 100644
index 0000000..f9a21de
--- /dev/null
+++ b/example/files/sonarqube-user-group.yml
@@ -0,0 +1,9 @@
+---
+apiVersion: user.openshift.io/v1
+kind: Group
+metadata:
+ name: sonarqube_user
+users:
+- developer
+- casual_user1
+- casual_user2
diff --git a/example/inventory/group_vars/all.yml b/example/inventory/group_vars/all.yml
index e153c4a..25ac9fb 100755
--- a/example/inventory/group_vars/all.yml
+++ b/example/inventory/group_vars/all.yml
@@ -21,6 +21,24 @@ sonarqube:
POSTGRES_DATABASE_NAME: "sonar"
openshift_cluster_content:
+- object: project
+ content:
+ - name: sonar project
+ file: "{{ playbook_dir}}/files/project.yml"
+ tags:
+ - project
+- object: user-groups
+ content:
+ - name: group-admin-members
+ file: "{{ playbook_dir}}/files/sonarqube-admin-group.yml"
+ namespace: "{{ ci_cd_namespace }}"
+ tags:
+ - users_and_groups
+ - name: group-view-members
+ file: "{{ playbook_dir}}/files/sonarqube-user-group.yml"
+ namespace: "{{ ci_cd_namespace }}"
+ tags:
+ - users_and_groups
- object: build
content:
- name: sonarqube
diff --git a/example/run.sh b/example/run.sh
index 60992e5..ef7ff9f 100755
--- a/example/run.sh
+++ b/example/run.sh
@@ -3,6 +3,8 @@
set -x
set -e
+rm -rf /opt/sonarqube/data/plugins/sonar-auth-openshift-plugin*.jar
+
## If the mounted data volume is empty, populate it from the default data
cp -a /opt/sonarqube/data-init/* /opt/sonarqube/data/
@@ -25,4 +27,4 @@ fi
java -jar lib/sonar-application-$SONAR_VERSION.jar \
-Dsonar.web.javaAdditionalOpts="${SONARQUBE_WEB_JVM_OPTS} -Djava.security.egd=file:/dev/./urandom" \
- "$@"
\ No newline at end of file
+ "$@"
diff --git a/example/sonar.properties b/example/sonar.properties
index c2a3547..85df06d 100644
--- a/example/sonar.properties
+++ b/example/sonar.properties
@@ -1,14 +1,18 @@
-sonar.log.console=true
-sonar.jdbc.username=${env:JDBC_USERNAME}
-sonar.jdbc.password=${env:JDBC_PASSWORD}
-sonar.jdbc.url=${env:JDBC_URL}
-sonar.forceAuthentication=${env:FORCE_AUTHENTICATION}
-sonar.authenticator.createUsers=${env:SONAR_AUTOCREATE_USERS}
-sonar.log.level=${env:SONAR_LOG_LEVEL}
-http.proxyHost=${env:PROXY_HOST}
-http.proxyPort=${env:PROXY_PORT}
-http.proxyUser=${env:PROXY_USER}
-http.proxyPassword=${env:PROXY_PASSWORD}
-kubernetes.service=https://${env:KUBERNETES_SERVICE_HOST}:${env:KUBERNETES_SERVICE_PORT}/
-sonar.auth.openshift.isEnabled=true
-sonar.auth.openshift.button.color=#000000
+sonar.log.console=true
+sonar.jdbc.username=${env:JDBC_USERNAME}
+sonar.jdbc.password=${env:JDBC_PASSWORD}
+sonar.jdbc.url=${env:JDBC_URL}
+sonar.forceAuthentication=${env:FORCE_AUTHENTICATION}
+sonar.authenticator.createUsers=${env:SONAR_AUTOCREATE_USERS}
+sonar.log.level=${env:SONAR_LOG_LEVEL}
+http.proxyHost=${env:PROXY_HOST}
+http.proxyPort=${env:PROXY_PORT}
+http.proxyUser=${env:PROXY_USER}
+http.proxyPassword=${env:PROXY_PASSWORD}
+kubernetes.service=https://${env:KUBERNETES_SERVICE_HOST}:${env:KUBERNETES_SERVICE_PORT}/
+sonar.auth.openshift.isEnabled=true
+sonar.auth.openshift.button.color=#000000
+sonar.auth.openshift.sar.groups=sonarqube_admin=sonar-administrators,sonarqube_user=sonar-users
+ignore.certs=false
+#oauth.cert=/opt/sonarqube/conf/oauth.crt
+
diff --git a/pom.xml b/pom.xml
index c797310..4f4abd1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,7 +7,7 @@
org.sonarsource.auth.openshift
sonar-auth-openshift-plugin
sonar-plugin
- 1.0.0
+ 1.1.0
OpenShift Authentication for SonarQube
getSARGroups() {
- String mapAsString = config.get("sonar.auth.openshift.sar.groups").orElse(DEFAULT_GROUPS);
+ String mapAsString = config.get(OPENSHIFT_GROUP_MAPPING).orElse(DEFAULT_GROUPS);
return Splitter.on(",").withKeyValueSeparator("=").split(mapAsString);
}
diff --git a/src/main/java/com/rhc/sonarqube/auth/openshift/OpenShiftIdentityProvider.java b/src/main/java/com/rhc/sonarqube/auth/openshift/OpenShiftIdentityProvider.java
index 7384a57..d94ae0f 100644
--- a/src/main/java/com/rhc/sonarqube/auth/openshift/OpenShiftIdentityProvider.java
+++ b/src/main/java/com/rhc/sonarqube/auth/openshift/OpenShiftIdentityProvider.java
@@ -14,12 +14,14 @@
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
import javax.servlet.http.HttpServletRequest;
import com.github.scribejava.core.model.Verb;
import com.github.scribejava.core.model.Response;
import com.github.scribejava.core.model.OAuthRequest;
import com.github.scribejava.core.oauth.OAuth20Service;
+import com.github.scribejava.httpclient.okhttp.OkHttpHttpClient;
import com.github.scribejava.core.model.OAuth2AccessToken;
import com.github.scribejava.core.builder.ServiceBuilder;
@@ -28,6 +30,7 @@
import org.sonar.api.server.authentication.UserIdentity;
import io.kubernetes.client.util.Config;
+import okhttp3.OkHttpClient;
import org.sonar.api.server.authentication.OAuth2IdentityProvider;
@@ -44,6 +47,7 @@ public class OpenShiftIdentityProvider implements OAuth2IdentityProvider {
private final OpenShiftScribeApi scribeApi;
private final OpenShiftConfiguration config;
+ private OkHttpClient okClient;
static final Logger LOGGER = Logger.getLogger(OpenShiftIdentityProvider.class.getName());
@@ -68,7 +72,7 @@ public OpenShiftIdentityProvider(OpenShiftConfiguration config, OpenShiftScribeA
private void initOpenShift() throws Exception {
try {
- setKeystore();
+ setHttpClient();
} catch (Exception ex) {
LOGGER.log(Level.SEVERE, "Problem setting up ssl", ex);
throw ex;
@@ -147,42 +151,27 @@ private void onCallback(CallbackContext context) throws InterruptedException, Ex
String code = request.getParameter("code");
OAuth2AccessToken accessToken = scribe.getAccessToken(code);
- Set sonarRoles = findSonarRoles(scribe, accessToken);
-
+ OpenShiftUserResponse user = getOpenShiftUser(scribe, accessToken);
+ Set sonarRoles = findSonarRoles(user);
LOGGER.fine(String.format("Roles %s", sonarRoles));
+ UserIdentity userIdentity = UserIdentity.builder().setGroups(sonarRoles).setProviderLogin(user.getUserName())
+ .setLogin(String.format("%s@%s", user.getUserName(), KEY)).setName(user.getUserName()).build();
- String user = getOpenShiftUser(scribe, accessToken);
- UserIdentity userIdentity = UserIdentity.builder().setGroups(sonarRoles).setProviderLogin(user)
- .setLogin(String.format("%s@%s", user, KEY)).setName(user).build();
+ LOGGER.fine(String.format("Set user: %s", userIdentity.getName()));
context.authenticate(userIdentity);
context.redirectToRequestedPage();
}
- private Set findSonarRoles(OAuth20Service scribe, OAuth2AccessToken accessToken)
- throws IOException, InterruptedException, ExecutionException {
- Response response = null;
+ private Set findSonarRoles(OpenShiftUserResponse user) {
HashSet sonarRoles = new HashSet();
- String namespace = config.getNamespace();
-
- OAuthRequest request = new OAuthRequest(Verb.POST, config.getSarURI());
- request.addHeader("Content-Type", "application/json");
- scribe.signRequest(accessToken, request);
for (String accessRole : config.getSARGroups().keySet()) {
- String json = OpenShiftSubjectAccessReviewRequest.createJsonRequest(accessRole, namespace);
- LOGGER.fine("SAR body " + json);
- request.setPayload(json);
-
- response = scribe.execute(request);
-
- if (response.isSuccessful()) {
- if (new JsonParser().parse(response.getBody()).getAsJsonObject().get("allowed").getAsBoolean()) {
- sonarRoles.add(config.getSARGroups().get(accessRole));
- }
- } else {
- LOGGER.warning(String.format("SAR Request failed with response message %s", response.getBody()));
+ if(user.isMemberOf(accessRole)) {
+ LOGGER.fine(String.format("Adding role %s", config.getSARGroups().get(accessRole)));
+ sonarRoles.add(config.getSARGroups().get(accessRole));
+ //LOGGER.fine(String.format("% has access to %s", user.getUserName(), config.getSARGroups().get(accessRole)));
}
}
return sonarRoles;
@@ -236,7 +225,8 @@ private void getServiceAccountName() throws IOException {
OAuth20Service scribe = newScribeBuilder().build(scribeApi);
OAuth2AccessToken token = new OAuth2AccessToken(config.getClientSecret());
try {
- String userName = getOpenShiftUser(scribe, token);
+ OpenShiftUserResponse user = getOpenShiftUser(scribe, token);
+ String userName = user.getUserName();
if (userName.indexOf(":") >= 0) {
config.setServicAccountName(userName.substring(userName.lastIndexOf(":") + 1));
LOGGER.info(String.format("Service account name '%s'", config.getServiceAccountName()));
@@ -247,8 +237,9 @@ private void getServiceAccountName() throws IOException {
}
- private String getOpenShiftUser(OAuth20Service scribe, OAuth2AccessToken accessToken)
+ private OpenShiftUserResponse getOpenShiftUser(OAuth20Service scribe, OAuth2AccessToken accessToken)
throws IOException, ExecutionException, InterruptedException {
+
OAuthRequest request = new OAuthRequest(Verb.GET, config.getUserURI());
scribe.signRequest(accessToken, request);
Response response = scribe.execute(request);
@@ -259,9 +250,8 @@ private String getOpenShiftUser(OAuth20Service scribe, OAuth2AccessToken accessT
}
String json = response.getBody();
LOGGER.fine("User response body ===== " + json);
- String userName = new JsonParser().parse(json).getAsJsonObject().get("metadata").getAsJsonObject().get("name")
- .getAsString();
- return userName;
+ OpenShiftUserResponse user = OpenShiftUserResponse.create(json);
+ return user;
}
private ServiceBuilder newScribeBuilder() throws IOException {
@@ -269,25 +259,43 @@ private ServiceBuilder newScribeBuilder() throws IOException {
throw new IllegalStateException("OpenShift authentication is disabled.");
}
- return new ServiceBuilder(config.getClientId()).apiSecret(config.getClientSecret()).callback(todoCallback);
+ OkHttpHttpClient httpClient = new OkHttpHttpClient(okClient);
+ return new ServiceBuilder(config.getClientId()).apiSecret(config.getClientSecret()).httpClient(httpClient).httpClient(httpClient).callback(todoCallback);
}
- private void setKeystore() throws IOException, GeneralSecurityException {
- KeyStore keyStore = SecurityUtils.getDefaultKeyStore();
- try {
- LOGGER.fine("Keystore size " + keyStore.size());
- } catch (Exception ex) {
- keyStore.load(null);
- }
+ private void setHttpClient() throws IOException, GeneralSecurityException {
+
+ if(config.ignoreCerts()) {
+ okClient = TrustAllHttpClient.instance();
+ LOGGER.warning("Ignoring all certs. Not meant for production use");
+ } else {
+
+ KeyStore keyStore = SecurityUtils.getDefaultKeyStore();
+ try {
+ LOGGER.fine("Keystore size " + keyStore.size());
+ } catch (Exception ex) {
+ keyStore.load(null);
+ }
+
+ FileInputStream fis = new FileInputStream(new File(config.getOpenShiftServiceAccountDirectory(), config.getCert()));
+ SecurityUtils.loadKeyStoreFromCertificates(keyStore, SecurityUtils.getX509CertificateFactory(), fis);
- FileInputStream fis = new FileInputStream(new File(config.getOpenShiftServiceAccountDirectory(), "ca.crt"));
- SecurityUtils.loadKeyStoreFromCertificates(keyStore, SecurityUtils.getX509CertificateFactory(), fis);
- LOGGER.fine("Keystore loaded");
- TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509", "SunJSSE");
- tmf.init(keyStore);
- SSLContext ssl = SSLContext.getInstance("TLS");
- ssl.init(Config.defaultClient().getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
- SSLContext.setDefault(ssl);
- LOGGER.fine("SSL context set");
+ fis = config.getOAuthCertFile();
+
+ if(fis != null) {
+ LOGGER.info("Loading OAuth certificate");
+ SecurityUtils.loadKeyStoreFromCertificates(keyStore, SecurityUtils.getX509CertificateFactory(), fis);
+ }
+
+ LOGGER.fine("Keystore loaded");
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509", "SunJSSE");
+ tmf.init(keyStore);
+ SSLContext ssl = SSLContext.getInstance("TLS");
+ ssl.init(Config.defaultClient().getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
+ SSLContext.setDefault(ssl);
+ LOGGER.fine("SSL context set");
+
+ okClient = new OkHttpClient.Builder().sslSocketFactory(ssl.getSocketFactory(), (X509TrustManager)tmf.getTrustManagers()[0]).build();
+ }
}
}
diff --git a/src/main/java/com/rhc/sonarqube/auth/openshift/OpenShiftScribeApi.java b/src/main/java/com/rhc/sonarqube/auth/openshift/OpenShiftScribeApi.java
index 4aaf422..a91b540 100644
--- a/src/main/java/com/rhc/sonarqube/auth/openshift/OpenShiftScribeApi.java
+++ b/src/main/java/com/rhc/sonarqube/auth/openshift/OpenShiftScribeApi.java
@@ -45,6 +45,7 @@ private void getWellKnown() throws IOException {
com.squareup.okhttp.Response okresponse = ok.newCall(okrequest).execute();
String json = okresponse.body().string();
+ LOGGER.fine(String.format("Well known response: %s", json));
JsonObject jsonObject = new JsonParser().parse(json).getAsJsonObject();
issuer = jsonObject.get("issuer").getAsString();
diff --git a/src/main/java/com/rhc/sonarqube/auth/openshift/OpenShiftSubjectAccessReviewRequest.java b/src/main/java/com/rhc/sonarqube/auth/openshift/OpenShiftSubjectAccessReviewRequest.java
deleted file mode 100644
index a32c06c..0000000
--- a/src/main/java/com/rhc/sonarqube/auth/openshift/OpenShiftSubjectAccessReviewRequest.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package com.rhc.sonarqube.auth.openshift;
-
-import java.util.ArrayList;
-import java.util.List;
-import com.google.api.client.util.Key;
-import com.google.gson.Gson;
-
-public class OpenShiftSubjectAccessReviewRequest {
-
- public static final String SUBJECT_ACCESS_REVIEW = "SubjectAccessReview";
- public static final String API_VERSION = "v1";
- public static final String RESOURCE = "sonarqube";
-
- public OpenShiftSubjectAccessReviewRequest() {
-
- kind = SUBJECT_ACCESS_REVIEW;
- apiVersion = API_VERSION;
- namespace = null;
- verb = null;
- resourceAPIGroup = "";
- resourceAPIVersion = "";
- resource = RESOURCE;
- resourceName = "";
- content = null;
- user = "";
- groups = new ArrayList();
- scopes = new ArrayList();
- }
-
- public static String createJsonRequest(String verb, String namespace) {
- OpenShiftSubjectAccessReviewRequest req = new OpenShiftSubjectAccessReviewRequest();
- req.verb = verb;
- req.namespace = namespace;
-
- return new Gson().toJson(req);
- }
-
- @Key
- public String kind;
-
- @Key
- public String apiVersion;
-
- @Key
- public String namespace;
-
- @Key
- public String verb;
-
- @Key
- public String resourceAPIGroup;
-
- @Key
- public String resourceAPIVersion;
-
- @Key
- public String resource;
-
- @Key
- public String resourceName;
-
- @Key
- public String content;
-
- @Key
- public String user;
-
- @Key
- public List groups;
-
- @Key
- public List scopes;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/main/java/com/rhc/sonarqube/auth/openshift/OpenShiftUserResponse.java b/src/main/java/com/rhc/sonarqube/auth/openshift/OpenShiftUserResponse.java
new file mode 100644
index 0000000..09a22df
--- /dev/null
+++ b/src/main/java/com/rhc/sonarqube/auth/openshift/OpenShiftUserResponse.java
@@ -0,0 +1,57 @@
+package com.rhc.sonarqube.auth.openshift;
+
+import java.util.List;
+
+import com.google.gson.Gson;
+
+
+public class OpenShiftUserResponse {
+ public List groups;
+ public MetaData metadata;
+
+ public OpenShiftUserResponse() {
+
+ }
+
+ public static OpenShiftUserResponse create(String json) {
+ return new Gson().fromJson(json, OpenShiftUserResponse.class);
+ }
+
+ public String getUserName() {
+ if(metadata != null) {
+ return metadata.name;
+ }
+
+ return null;
+ }
+
+ public boolean isMemberOf(String groupName) {
+ if(groups == null) {
+ return false;
+ }
+
+ return groups.contains(groupName);
+ }
+
+ public class MetaData {
+ public String name;
+
+ public String toString() {
+ return (name);
+ }
+ }
+
+ public String toString() {
+ if(metadata == null) {
+ return "OpenShiftUserResponse - username not set";
+ }
+
+ return new StringBuilder("OpenShiftUserResponse: name: ").append(metadata).append(" groups: ").append(groups).toString();
+ }
+
+ public static void main( ) {
+
+
+ }
+
+}
diff --git a/src/main/java/com/rhc/sonarqube/auth/openshift/TrustAllHttpClient.java b/src/main/java/com/rhc/sonarqube/auth/openshift/TrustAllHttpClient.java
new file mode 100644
index 0000000..730e118
--- /dev/null
+++ b/src/main/java/com/rhc/sonarqube/auth/openshift/TrustAllHttpClient.java
@@ -0,0 +1,70 @@
+package com.rhc.sonarqube.auth.openshift;
+
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.util.logging.Logger;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
+import okhttp3.OkHttpClient;
+
+/**
+ * Provide a way to circumvent certificate verifcation. Not meant for production use
+ * @author mcanoy
+ *
+ */
+public class TrustAllHttpClient {
+ static final Logger LOGGER = Logger.getLogger(TrustAllHttpClient.class.getName());
+
+
+ public static OkHttpClient instance() {
+
+ final TrustManager[] trustAllCerts = new TrustManager[] {
+ new X509TrustManager() {
+
+ @Override
+ public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
+ }
+
+ @Override
+ public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
+ }
+
+ @Override
+ public java.security.cert.X509Certificate[] getAcceptedIssuers() {
+ return new java.security.cert.X509Certificate[]{};
+ }
+ }
+ };
+
+ SSLContext trustAllSslContext = null;
+
+ try {
+ trustAllSslContext = SSLContext.getInstance("SSL");
+ trustAllSslContext.init(null, trustAllCerts, new java.security.SecureRandom());
+ } catch (NoSuchAlgorithmException | KeyManagementException e) {
+ throw new RuntimeException(e);
+ }
+
+ final SSLSocketFactory trustAllSslSocketFactory = trustAllSslContext.getSocketFactory();
+
+ LOGGER.warning("Using the trustAllSslClient is highly discouraged and should not be used in Production!");
+
+ OkHttpClient okClient = new OkHttpClient.Builder()
+ .sslSocketFactory(trustAllSslSocketFactory, (X509TrustManager)trustAllCerts[0])
+ .hostnameVerifier(new HostnameVerifier() {
+ @Override
+ public boolean verify(String hostname, SSLSession session) {
+ return true;
+ }
+ }).build();
+
+ return okClient;
+ }
+}
diff --git a/src/test/java/com/rhc/sonarqube/auth/openshift/OpenShiftUserTest.java b/src/test/java/com/rhc/sonarqube/auth/openshift/OpenShiftUserTest.java
new file mode 100644
index 0000000..546d0c1
--- /dev/null
+++ b/src/test/java/com/rhc/sonarqube/auth/openshift/OpenShiftUserTest.java
@@ -0,0 +1,18 @@
+package com.rhc.sonarqube.auth.openshift;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class OpenShiftUserTest {
+
+
+ @Test
+ public void testUser() {
+ String user = "{\"kind\":\"User\",\"apiVersion\":\"user.openshift.io/v1\",\"metadata\":{\"name\":\"developer\",\"selfLink\":\"/apis/user.openshift.io/v1/users/developer\",\"uid\":\"c7e4c4da-e150-11e9-abd6-0a580a80009a\",\"resourceVersion\":\"230428\",\"creationTimestamp\":\"2019-09-27T18:01:07Z\"},\"identities\":[\"htpasswd_provider:developer\"],\"groups\":[\"group1\",\"sonarqube_admin\",\"system:authenticated\",\"system:authenticated:oauth\"]}";
+ OpenShiftUserResponse openshiftUser = OpenShiftUserResponse.create(user);
+
+ Assert.assertEquals("developer", openshiftUser.getUserName());
+ Assert.assertTrue(openshiftUser.isMemberOf("sonarqube_admin"));
+
+ }
+}
diff --git a/src/test/java/com/rhc/sonarqube/auth/openshift/test/MockHttpClient.java b/src/test/java/com/rhc/sonarqube/auth/openshift/test/MockHttpClient.java
index 5574476..d014af5 100644
--- a/src/test/java/com/rhc/sonarqube/auth/openshift/test/MockHttpClient.java
+++ b/src/test/java/com/rhc/sonarqube/auth/openshift/test/MockHttpClient.java
@@ -46,8 +46,8 @@ public Future executeAsync(String userAgent, Map headers,
@Override
public Response execute(String userAgent, Map headers, Verb httpVerb, String completeUrl,
byte[] bodyContents) throws InterruptedException, ExecutionException, IOException {
-
- if(completeUrl.contentEquals("http://127.0.0.1/oapi/v1/users/~")) {
+
+ if(completeUrl.contentEquals("http://127.0.0.1/apis/user.openshift.io/v1/users/~")) {
return new Response(200, "message", new HashMap(),
new FileInputStream("src/test/resources/service_account_user.json"));
} else if(completeUrl.contentEquals("http://127.0.0.1/apis/route.openshift.io/v1/namespaces/sqube/routes/sonarqube")) {