shift7-ch / katta-server

Zero-config storage management and zero-knowledge key management for teams and organizations.
GNU Affero General Public License v3.0
0 stars 0 forks source link

[Story] Scoped Access Tokens through Authorization Services / UMA #41

Closed chenkins closed 1 year ago

chenkins commented 1 year ago

Story

Acceptance Criteria

Open Questions

Context

Implementation

chenkins commented 1 year ago

Problem: we want to avoid sending a token to AssumeRoleWithWebIdentity that grows with the number of vaults/roles added to the user.

Two options:

Preliminary decision: try out (1) to see how it looks like eventually.

chenkins commented 1 year ago

Test for (2):

function jwtd() {
    if [[ -x $(command -v jq) ]]; then
         jq -R 'split(".") | .[0],.[1] | @base64d | fromjson' <<< "${1}"
         echo "Signature: $(echo "${1}" | awk -F'.' '{print $3}')"
    fi
}
TOKEN=`curl -v -X POST http://localhost:8180/realms/cryptomator/protocol/openid-connect/token \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "client_id=cryptomator" \
     -d "scope=openid" \
     -d "grant_type=password" \
     -d "username=admin" \
     -d "password=admin"    | jq ".access_token" | tr -d '"'`
jwtd $TOKEN     
SCOPED_TOKEN=`curl -X POST http://localhost:8180/realms/cryptomator/protocol/openid-connect/token\
    -d "client_id=cryptomator" \
    --data-urlencode "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \
    -d "subject_token=$TOKEN" \
    -d "subject_issuer=http://localhost:8180/realms/cryptomator" \
    --data-urlencode "subject_token_type=urn:ietf:params:oauth:token-type:access_token" \
    -d "audience=cryptomatorvaults" \
    -d "scope=openid c1089d35-0abe-4e51-ab58-ed8c1507efca" | jq ".access_token" | tr -d '"'`
jwtd $SCOPED_TOKEN      
chenkins commented 1 year ago

Problem: the token we create buckets with has all realm and client roles mapped into it by default. Two options:

Snippets for patching Keycloak.js (unfinished business):

 public async tokenExchange(): string{
    this.keycloak.tokenExchange = function(){
        var kc = this;

        var params = 'grant_type=urn:ietf:params:oauth:grant-type:token-exchange"&' + 'subject_token=' + kc.accessToken;

        return new Promise(function (resolve, reject) {

            var url = kc.endpoints.token();
            var req = new XMLHttpRequest();
            req.open('POST', url, true);
            req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
            req.withCredentials = true;

            params += '&client_id=' + encodeURIComponent(kc.clientId);

            var timeLocal = new Date().getTime();

            req.onreadystatechange = function () {
                if (req.readyState == 4) {
                    if (req.status == 200) {
                        console.log('[KEYCLOAK] Token refreshed');

                        timeLocal = (timeLocal + new Date().getTime()) / 2;

                        var tokenResponse = JSON.parse(req.responseText);

                        kc.onAuthRefreshSuccess && kc.onAuthRefreshSuccess();
                        resolve(tokenResponse['access_token'], tokenResponse['refresh_token'], tokenResponse['id_token'], timeLocal);
                    } else {
                        console.log('[KEYCLOAK] Failed to refresh token');

                        if (req.status == 400) {
                            kc.clearToken();
                        }

                        kc.onAuthRefreshError && kc.onAuthRefreshError();
                        reject();
                    }
                }
            };
            req.send(params);
        });
    };
    await this.keycloak.tokenExchange();
    return this.keycloak.token;
  }
chenkins commented 1 year ago

N.B. Without roles.client.realm-management in dev-realm.json, we get: 2023-11-20 14:01:40 2023-11-20 13:01:40,731 ERROR [org.keycloak.services.error.KeycloakErrorHandler] (executor-thread-1) Uncaught server error: java.lang.RuntimeException: Unable to find composite client role: realm-admin