ACCESS::oauth

Description

This command returns a JSON Web Signature token based on provided payload and signed with the provided JWK object. When the specified JWK object does not specify a JWS signing algorithm, an additional signing algorithm is required and must be provided with the -alg option. Unless specified with the -header option, JOSE header section of JWS will be derived and auto-generated from the available JWK object and signing algorithm, and the generated JOSE header will include a signing algorithm, and JWK key ID or certificate SHA-1 thumbprint or SHA-256 thumbprint whichever is available first in that order. When the specified JWK object contains a certificate, this command by default ensures that only a certificate with a valid expiration is allowed to be used , unless the -ignore-cert-expiry option is specified.
Note: Requires APM module.

Syntax

ACCESS::oauth sign [ -header <raw-data> ] -payload <raw-data> -key <JWK object> [ -alg <signing algorithm> ] [ -ignore-cert-expiry ]

Examples

when RULE_INIT {
    # This is an example of using ACCESS::oauth sign command to perform
    # JWT access token resigning.
    # Here we predefined the list of incoming claims which BIG-IP
    # needs to include in the JWT. Here we assumed there is an OAuth Scope
    # Agent configured, which produces the session variables for each claim.
    # Once the JWT payload is constructed, here we use ACCESS::oauth sign
    # command to sign the payload, and produce a JWS.
    set static::claim_list_string { {sub} {name} }
    set static::claim_list_boolean_int { {admin} }
    set static::jws_cache {oauth-sign-test-jws_cache}
    set static::jwt_issuer {https://myissuer.com}
    set static::jwt_sess_var_name {session.oauth.scope.last.jwt}
    set static::jwt_expires_in 10
    set static::jwt_leeway 0
    set static::jwt_sdb_timeout_adjustment 3
}

proc gettimeofday {} {
    return [ clock seconds ]
}

proc generate_payload { claim_list_string claim_list_boolean_int } {
    set payload "\{"
    append payload {"issuer":"} $static::jwt_issuer {"}
    set iat [ call gettimeofday ]
    append payload {,"iat":} $iat
    append payload {,"exp":} [ expr { $iat + $static::jwt_expires_in } ]
    append payload {,"nbf":} [ expr { $iat - $static::jwt_leeway } ]
    foreach claim $claim_list_string {
        set value [ ACCESS::session data get "$static::jwt_sess_var_name.$claim" ]
        if { [ string length value ] == 0 } {
            continue
        }
        append payload {,"} $claim {":"} $value {"}
    }
    foreach claim $claim_list_boolean_int {
        set value [ ACCESS::session data get "$static::jwt_sess_var_name.$claim" ]
        if { [ string length value ] == 0 } {
            continue
        }
        append payload {,"} $claim {":} $value
    }
    append payload "\}"
    return $payload
}

proc generate_jws {} {
    set payload [ call generate_payload $static::claim_list_string $static::claim_list_boolean_int ]
    return [ ACCESS::oauth sign -payload $payload -alg RS512 -key /Common/jwk-rsa-2 -ignore-cert-expiry ]
}

proc get_user_key {} {
    set data [ ACCESS::session sid ]
    binary scan [ md5 $data ] H* data
    return $data
}

proc get_user_key_from_sdb {} {
    return [ ACCESS::session data get {session.jwt.cache.user_key} ]
}

proc set_user_key_to_sdb {} {
    ACCESS::session data set {session.jwt.cache.user_key} [ call get_user_key ]
}

proc calc_sdb_timeout {} {
    return [ expr { $static::jwt_expires_in - $static::jwt_sdb_timeout_adjustment } ]
}

proc get_jws_from_cache {} {
    set user_key [ call get_user_key ]
    set jws [ table lookup -notouch -subtable $static::jws_cache $user_key ]
    if { [ string length $jws ] != 0 } {
        return $jws
    }
    return [ table set -notouch -subtable $static::jws_cache -excl $user_key [ call generate_jws ] [ call calc_sdb_timeout ]  [ call calc_sdb_timeout ] ]
}

proc get_jws { from_cache } {
    if { $from_cache == "yes" } {
        return [ call get_jws_from_cache ]
    } else {
        return [ call generate_jws ]
    }
}

proc delete_jws_cache {} {
    set user_key [ call get_user_key_from_sdb ]
    ACCESS::log "Delete cache for $user_key"
    table delete -subtable $static::jws_cache $user_key
}

when ACCESS_SESSION_STARTED {
    call set_user_key_to_sdb
}

when ACCESS_ACL_ALLOWED {
    set jws [call get_jws "yes" ]
    HTTP::header replace Authorization "Bearer $jws"
}

when ACCESS_SESSION_CLOSED {
    call delete_jws_cache
}