Skip to content

Commit

Permalink
CORE-1027: added some endpoints to allow administrators to get impers…
Browse files Browse the repository at this point in the history
…onation tokens
  • Loading branch information
slr71 committed Jun 22, 2020
1 parent c39ccbc commit 86a3ebc
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 1 deletion.
27 changes: 27 additions & 0 deletions resources/docs/get-admin-token.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
This service allows administrative users to obtain an impersonation token in order to act on behalf of another
user. This feature is useful for troubleshooting in cases where a user is seeing a problem that the administrator can't
reproduce. You must be logged in using HTTP basic authorization to use this endpoint. The token endpoints are the only
endpoints that use basic authorization. To log in, click the Authorize button above, enter your username and password
under `Basic authentication`, and click the Authorize button underneath the password text box.

Once you have the access token, you can use it to authorize calls to other endpoints in the Swagger UI. First, remove
the basic authentication credentials by clicking the Authorize button above and clicking the Logout button in the `Basic
authenitcation` section of authorization window. Second, click the Authorization button again and type the word `Bearer`
followed by a single space in the Value text box of the `Api key authorization` section of the window. Paste in the
access token from this endpoint's response body then click the Authorize button underneath the Value text box.

You can use `curl` and `jq`, which is available from [the jq web site](https://stedolan.github.io/jq/), to obtain an
access token from the command line. The easiest way to do this on Unix-like operating systems is to define an
environment variable containing the authorization header:

```
export AUTH_HEADER=\"Authorization: Bearer $(curl -su username https://de.cyverse.org/terrain/admin/token?username=foo \
| jq -r .access_token)\"
```

Once you have the authorization header stored in an environment variable, you can include it in calls to other Terrain
endpoints:

```
curl -sH \"$AUTH_HEADER\" \"https://de.cyverse.org/terrain/apps?search=word\"
```
12 changes: 12 additions & 0 deletions src/terrain/clients/keycloak.clj
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,15 @@
:username username
:password password}
:as :json})))

(defn get-impersonation-token
"Obtains an impersonation token for troubleshooting purposes."
[subject-token username]
(:body (http/post (keycloak-url "protocol" "openid-connect" "token")
{:form-params {:grant_type "urn:ietf:params:oauth:grant-type:token-exchange"
:client_id (config/keycloak-client-id)
:client_secret (config/keycloak-client-secret)
:subject_token subject-token
:requested_token_type "urn:ietf:params:oauth:token-type:access_token"
:requested_subject username}
:as :json})))
2 changes: 2 additions & 0 deletions src/terrain/routes.clj
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@
(defn unsecured-routes
[]
(util/flagged-routes
(admin-token-routes)
(token-routes)
(unsecured-misc-routes)
(unsecured-notification-routes)))
Expand Down Expand Up @@ -247,6 +248,7 @@
{:name "admin-reference-genomes", :description "Admin Reference Genome Endpoints"}
{:name "admin-requests", :description "Admin Request Endpoints"}
{:name "admin-settings", :description "Admin Setting Endpoints"}
{:name "admin-token", :description "Admin OAuth Tokens"}
{:name "admin-tools", :description "Admin Tool Endpoints"}
{:name "admin-tool-requests", :description "Admin Tool Request Endpoints"}
{:name "admin-user-info", :description "User Info Administration Endpoints"}
Expand Down
3 changes: 3 additions & 0 deletions src/terrain/routes/schemas/token.clj
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,6 @@

(optional-key :scope)
(describe String "The scopes granted to the access token")})

(defschema AdminKeycloakTokenParams
{:username (describe String "The username of the person to impersonate")})
20 changes: 20 additions & 0 deletions src/terrain/routes/token.clj
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,23 @@
:return AccessTokenResponse
:description-file "docs/get-token.md"
(oauth/get-keycloak-token authorization)))))

(defn admin-token-routes
[]
(routes
(context "/admin/token" []
:tags ["admin-token"]

(GET "/" [:as {{:strs [authorization]} :headers}]
:query [{:keys [username]} AdminKeycloakTokenParams]
:summary "Obtain Impersonation Tokens"
:return AccessTokenResponse
:description-file "docs/get-admin-token.md"
(oauth/get-admin-token authorization username))

(GET "/keycloak" [:as {{:strs [authorization]} :headers}]
:query [{:keys [username]} AdminKeycloakTokenParams]
:summary "Obtain Keycloak OIDC Impersonation Tokens"
:return AccessTokenResponse
:description-file "docs/get-admin-token.md"
(oauth/get-keycloak-admin-token authorization username)))))
12 changes: 11 additions & 1 deletion src/terrain/services/oauth.clj
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,15 @@
(http-response/ok (keycloak/get-token username password))
(http-response/unauthorized)))

;; Make CAS the default identity provider for now.
;; Make CAS the default identity provider for standard tokens for now.
(def get-token get-cas-token)

(defn get-keycloak-admin-token [authorization username]
(if-let [[username password] (get-basic-auth-credentials authorization)]
(http-response/ok (-> (keycloak/get-token username password)
:access_token
(keycloak/get-impersonation-token username)))
(http-response/unauthorized)))

;; Make Keycloak the default identity provider for impersonation tokens.
(def get-admin-token get-keycloak-admin-token)

0 comments on commit 86a3ebc

Please sign in to comment.