OAuth SSO
Hi All, we'd like to secure the access to a backend portal with OAuth (F5 Authorization Server and F5 Client/Ressource Server). We aleady configured 2 Virtual Servers and 2 Access Profiles access profile 1 for the backend application (OAuth Client and Scope Agents) access profile 2 for the OAuth AS (Logon Page, LDAP Auth and OAuth AS Agent) The login and the OAuth (OIDC) works with the backend via id_token. Idea was to ask the user ONCE for his LDAP Credentials and then authorize the user in subsequent authorization requests from client applications WITHOUT asking for entering his credentials again. What we see in the session logs is, that the authorization server session always ends with "session deleted (oauth_finished)" once the authorization request has successfully ended, hence the users LDAP information is destroyed together with the "session deleted" Is it possible to get some kind of SSO so that the users credentials is stored in the client for subsequent authorization requests and that the logon page can make use those credentials without prompting the user to login manually again? Thanks Steffen432Views2likes3CommentsBIGIP OAUTH : Transmit "Application id" to backend server after a successful atuthentication
Hello @ all 🙂 I took over the management of a bigip (15.1.1) on which APM is configured, in particular to do OAUTH for partner applications. I'd like to know if it is possible to transmit used application id (from "Access ›› Federation : OAuth Authorization Server : Client Application " ) to backend server. Here is what I had understood about how it works (currently functionnal): External form, when "Authentication button" is clicked, redirect to a form hosted and managed with APM on our F5. An Access policy is used and when user is authenticated, the brower redirect to the external application using one of the defined url for the current Application ("Access ›› Federation : OAuth Authorization Server : Client Application " : Security settings/Redirect URL(s) ). Then, the next requests are authenticated. I'd like to know if it is possible (and how) add an information that could be transmitted to backend server to identify the used application. Little precision : we can't change the current behavior of the external app : it means that the solution should be on the BigIP. Thank you for your helpSolved1.1KViews0likes10CommentsUsing Custom OAuth Client iRules
How do I use iRules with OAuth Server Profile? What are the valid events that will fire to trigger execution. Products docs just say "attach and iRule if you want customization". https://support.f5.com/kb/en-us/products/big-ip_apm/manuals/product/apm-authentication-sso-13-1-0/37.html Under heading "Configuring OAuth servers for APM as a client"556Views2likes2CommentsOAuth SSO like SAML Inline SSO possible?
Hi Folks, I have the following challenge and I am unsure, how it can be solved. F5 APM as OAuth Authorization Server Web Application as OAuth Client + Ressource Server Szenario 1: Internal Access This works like a charme. The user go's to the Web Application, clicks on the OIDC Login Link, is redirected to the Authorization Server, etc. The classic grant flow. Szenario 2: External Access through APM Portal The customer demand is, to publish this web application through a F5 APM Webtop with single sign on. The Web Application does not support getting the JWT from the authorization header, therefore all Bearer SSO methodes are not working. The application must go through the OAuth Grant Flow transparently for the user. This looks like the SAML Inline SSO method, but that is not possible with OAuth or do I miss anything? I have two ideas, how this can be solved. It would be great, If someone knows an even simpler method. Publish the OAuth Server in the internet. Publish the Web Application through a new Virtual Server with an Access Profile attached. Add Portal Link to the Web Application. Span the access session accross both Access Profiles. Opening the Web Application from the Web Top -> works seamless with the same Access Session Clicking on the OIDC Login Link at the Web Application Redirect to the OAuth Server New Access Session begins and the user must login again -> BAD The new access session for the Authorization server is required, because: The Access Policy must be validated to trigger the OAuth Authorization VPE Agent. The Access Policy is closed automatically after OAuth Authorization. First idea: At initial login on the Webtop: Generate a secure domain cookie Set it in the browser Write a mapping table (ltm table) cookie->username At the OAuth Server: Get the cookie Lookup the username in the mapping table If found, set the OAuth username, else prompt for authentication OAuth Authorization works without user login again Second idea: At initial auth-redirect Request from the Web Application: Intercept the auth-redirect request Use a sideband connection to request the authorization code from the authorization server (skip authentication, authorization server is only available on the f5 itself) Use another sideband connection to send the authorization code via the redirect-request back to the Web Application Use the redirect-request response as the response for 1. and deliver it to the browser This are the only two ideas I have, too solve this challenge. However, is it really as complex as I think or is there a really simple method I have overseen?1.2KViews0likes4CommentsAPM Oauth clintless mode
Hi, We currently have the following setup: client( not a web browser) sends a post request to an internal oauth server with the following parameters: username: some_user password: some_pass scope: some_scope grant_type: some_grant if the client passes the authentication he receives a bearer access token which is inserted to the header on the response. Then he can access and use the rest api. We want to integrate F5 into the current scenario so it will act as a client/resource provider( I hope those are the right terms) and then will check the validity of the access token. I'm pretty new to all of the terms and the process of getting an access token, I have read couple of posts on devcentral, guides on f5 clouddocs and on ask f5 and started to play around with it. Those are the resources I've used so far: https://devcentral.f5.com/questions/apm-authentication-for-a-sessionless-and-clientless-api-62162 https://clouddocs.f5.com/training/community/iam/html/class2/module1/module1.html https://support.f5.com/kb/en-us/products/big-ip_apm/manuals/product/big-ip-access-policy-manager-single-sign-on-concepts-configuration-14-1-0/04.html https://support.f5.com/kb/en-us/products/big-ip_apm/manuals/product/big-ip-access-policy-manager-authentication-and-single-sign-on-14-0-0/38.html I have a very general idea how its supposed to work: Client sends a POST request to a VS with apm. An irule will check the request and insert clientless mode. somehow I need to parse the POST parameters and assign them to the appropriate APM variables. There must be a provider configuration and a request configuration ( with the appropriate variables which were parsed ). F5 requests an access token from the oauth server and if successful then on the response it inserts a bearer header with the received access token. The client sends requests to the api which is configured behind a different VS with a per request AP which will verify his bearer token and the scope with the Oauth server. I would like to know if that's something possible to achieve and where and how to start. Thanks, Alex584Views0likes1CommentOAuth 2.0 Dynamic Client Registration
Problem this snippet solves: OAuth 2.0 is now supported in version 13. Client applications need to be defined manually in the Web UI. We developed an irule allowing a client application to self register. How to use this snippet: This code makes calls to external functions : json2dict and HTTP Super SIDEBAND Requestor. You need to add them to your set of irules on the BIG-IP before configuring the client app registration service. json2dict proc json2dict JSONtext { string range [ string trim [ string trimleft [ string map {\t {} \n {} \r {} , { } : { } \[ \{ \] \}} $JSONtext ] {\uFEFF} ] ] 1 end-1 } Workflow The client application will do the following request : POST /f5-oauth2/v1/client-register HTTP/1.1 Host: oauthas.example.com User-Agent: curl/7.47.1 Accept: */* Content-Length: 29 Content-Type: application/x-www-form-urlencoded username=user&password=pwd This request can be achieved using cURL : curl -k -vvv https://oauthas.example.com/f5-oauth2/v1/client-register -d 'username=user&password=pwd' Quick notes The irule is configured to create Client Applications with Resource Owner Password Credentials Grant (ROPC) mode activated. The irule needs to be modified to activate other modes Update (2018-05-01) Add a way to configure static client_id and client_secret Update (2018-01-12) URI decode username and password parameters Update (2017-11-07) Use HTTP::collect to workaround issues with large body Update (2017-10-25) Enhance JSON result parsing and attribute retrieval Code : when RULE_INIT { ### # credentials required to access iControl REST API ### set static::adm_user "admin" set static::adm_pwd "admin" ### # settings required to authenticate the user trying to register an application ### set static::timeout 300 set static::lifetime 300 set static::access_profile "/Common/ap-ldap-auth" ### # settings required to update the APM configuration with the newly created ClientApp configuraiton ### set static::adm_partition "Common" set static::oauth_profile "my-oauth-profile" set static::scopes "myscope" ### # settings required to sync the OAuth 2.0 Authorization Server access profile ### set static::oauth_access_policy "ap-oauth-auth-server" ### # settings required to publish the client registration service ### set static::client_register_uri "/f5-oauth2/v1/client-register" set static::host "oauthas.example.com" ### # Define a static client_id and client_secret ### set static::use_static_app 1 set static::client_id "xxxxxxxxxxxxxxxxxxxxxxx" set static::client_secret "xxxxxxxxxxxxxxxxxxx" } when CLIENT_ACCEPTED { ### # When we accept a connection, create an Access session and save the session ID. ### set flow_sid [ACCESS::session create -timeout $static::timeout -lifetime $static::lifetime] } when HTTP_REQUEST { ### # initialize vars ### set username "" set password "" set name "" set client_app "" set scopes "" set client_id "" set client_secret "" set agent "" set timestamp [clock seconds] switch -glob [string tolower [HTTP::header "User-Agent"]] { "*android*" { set agent "android" } "*ios*" { set agent "ios" } default { set agent "default" } } ### # identify client registration request. The client applicaiton needs to do a POST request on client registration URI and provides username and password ### if { [HTTP::path] eq $static::client_register_uri and [HTTP::host] eq $static::host and [HTTP::method] eq "POST" } { HTTP::collect [HTTP::header Content-Length] } } when HTTP_REQUEST_DATA { set username [URI::decode [URI::query "/?$payload" username]] set password [URI::decode [URI::query "/?$payload" password]] ### # play inline ACCESS policy to validate user credentials ### ACCESS::policy evaluate -sid $flow_sid -profile $static::access_profile session.logon.last.username $username session.logon.last.password $password session.server.landinguri [string tolower [HTTP::path]] if { [ACCESS::policy result -sid $flow_sid] eq "deny" or [ACCESS::policy result -sid $flow_sid] eq "not_started" } { HTTP::respond 403 content "{\"error\": \"Invalid user credentials\",\"error-message\": \"Access denied by Acces policy\"}" noserver Content-Type "application/json" Connection Close ACCESS::session remove -sid $flow_sid event disable all } ACCESS::session remove -sid $flow_sid if { !$static::use_static_app } { ### # generate client name and client application name ### set username [string map -nocase { "@" "." } $username] set name "$username-$agent-$timestamp" set client_app $name set scopes $static::scopes ### # prepare and execute API REST call to create a new client application. Endpoint: /mgmt/tm/apm/oauth/oauth-client-app ### set json_body "{\"name\": \"$name\",\"appName\": \"$client_app\",\"authType\": \"secret\",\"grantPassword\": \"enabled\",\"scopes\": \"$scopes\"}" set status [call /Common/HSSR::http_req -state hstate -uri "http://127.0.0.1:8100/mgmt/tm/apm/oauth/oauth-client-app" -method POST -body $json_body -type "application/json; charset=utf-8" -rbody rbody -userid $static::adm_user -passwd $static::adm_pwd ] set json_result [call /Common/sys-exec::json2dict $rbody] if { $status contains "200" } { ### # extract client_id and client_secret from JSON body ### set client_id [lindex $json_result [expr {[lsearch $json_result "clientId"]+1}]] set client_secret [lindex $json_result [expr {[lsearch $json_result "clientSecret"]+1}]] ### # prepare and execute API REST call to bind the client application to the OAuth profile. Endpoint: /mgmt/tm/apm/profile/oauth/~$static::adm_parition~$static::oauth_profile/client-apps ### set json_body "{\"name\": \"$name\"}" set status [call /Common/HSSR::http_req -state hstate -uri "http://127.0.0.1:8100/mgmt/tm/apm/profile/oauth/~$static::adm_partition~$static::oauth_profile/client-apps" -method POST -body $json_body -type "application/json; charset=utf-8" -rbody rbody -userid $static::adm_user -passwd $static::adm_pwd ] set json_result [call /Common/sys-exec::json2dict $rbody] ### # if binding is successful, respond to the client with client_id and client_secret ### if { $status contains "200" } { ### # Prepare and execute API REST call to apply Access Profile after Client Application has been assigned to OAuth profile ### set json_body "{\"generationAction\": \"increment\"}" set status [call /Common/HSSR::http_req -state hstate -uri "http://127.0.0.1:8100/mgmt/tm/apm/profile/access/~$static::adm_partition~$static::oauth_access_policy" -method PATCH -body $json_body -type "application/json; charset=utf-8" -rbody rbody -userid $static::adm_user -passwd $static::adm_pwd ] set json_result [call /Common/sys-exec::json2dict $rbody] if { $status contains "200" } { HTTP::respond 200 content "{\"client_id\": \"$client_id\",\"client_secret\": \"$client_secret\"}" noserver Content-Type "application/json" Connection Close event disable all } else { HTTP::respond 403 content "{\"error\": \"Synchronization failed\",\"error-message\": \"[lindex $json_result 3]\"}" noserver Content-Type "application/json" Connection Close event disable all } } else { HTTP::respond 403 content "{\"error\": \"ClientApp binding failed\",\"error-message\": \"[lindex $json_result 3]\"}" noserver Content-Type "application/json" Connection Close event disable all } } else { HTTP::respond 403 content "{\"error\": \"ClientApp creation failed\",\"error-message\": \"[lindex $json_result 3]\"}" noserver Content-Type "application/json" Connection Close event disable all } } else { HTTP::respond 200 content "{\"client_id\": \"$static::client_id\",\"client_secret\": \"$static::client_secret\"}" noserver Content-Type "application/json" Connection Close event disable all } } Tested this on version: 13.01.1KViews0likes8CommentsRate Limiting based on ACCESS TOKEN (OAuth 2.0)
Problem this snippet solves: When publishing web services, you need to implement some rate limiting functions to avoid abuses. There are plenty of ways to setup Rate limiting How to use this snippet: The code below setup a rate limiting based on the ACCESS TOKEN. The client will receive a response "429 Too much requests" after 1000 requests in a window of 300 seconds. The client can request its current status by doing a request to /rate_limit_status. He will then receive the following JSON message : { "x-rate-limit-limit": 1000, "x-rate-limit-remaining": 800, "x-rate-limit-reset": 100 } Code : when RULE_INIT { ### # rate limit options ### set static::request_limit 1000 set static::window_size 300 ### # define URI endpoints ### set static::status_uri "/rate_limit_status" } when HTTP_REQUEST { ### # initialize vars ### set access_token "" set client_ip "" ### # retrieve the access_token. It will be used as a mandatory key to evaluate rate limiting ### if { [HTTP::header exists Authorization] and [HTTP::header Authorization] contains "Bearer" } { set access_token [getfield [HTTP::header Authorization] " " 2] set client_ip [IP::client_addr] } if { !($access_token eq "") } { ### # provide client with rate limit status ### set key [sha1 $access_token] set count [table lookup -notouch $key] set time [table timeout -remaining $key] ### # Provide a status page to the client ### if { [HTTP::path] eq $static::status_uri and [HTTP::method] eq "GET" } { if { $count > 0 } { set x_rate_limit_limit "$static::request_limit" set x_rate_limit_remaining "[expr {$static::request_limit-$count}]" set x_rate_limit_reset "$time" } else { set x_rate_limit_limit "$static::request_limit" set x_rate_limit_remaining "$static::request_limit" set x_rate_limit_reset "$static::window_size" } HTTP::respond 200 content "{\"x-rate-limit-limit\": $x_rate_limit_limit,\"x-rate-limit-remaining\": $x_rate_limit_remaining,\"x-rate-limit-reset\": $x_rate_limit_reset}" noserver Content-Type "application/json" Connection Close event disable all } else { ### # Handle the case where a client reach the rate limit ### if { $count >= $static::request_limit } { set x_rate_limit_limit "$static::request_limit" set x_rate_limit_remaining "0" set x_rate_limit_reset "$time" HTTP::respond 429 content "{\"x-rate-limit-limit\": $x_rate_limit_limit,\"x-rate-limit-remaining\": $x_rate_limit_remaining,\"x-rate-limit-reset\": $x_rate_limit_reset}" noserver Content-Type "application/json" Connection Close event disable all } else { if { $count == 0 } { table add $key 1 $static::window_size $static::window_size } else { table incr -notouch $key } } } } } Tested this on version: 11.5717Views0likes1CommentF5 Oauth server introspect JWT access token from external server
dear all, I already have setup a F5 as oauth client, F5 as oauth server (AS) and F5 as API gateway where F5 performs the introspect internally in its oauth database. So that is all working fine. Now we would like to perform introspect from an external server / API gateway towards the F5 and we are using JWT access tokens generated by F5 oauth server. I would assume the endpoint is /f5-oauth2/v1/introspect and we should define resource-server-id, resource-server-secret and access-token. According to the F5 documentation it is used only for Opaque tokens but that is not recommended as best practice is to use JWT. /f5-oauth2/v1/introspect as token introspection endpoint for validating Opaque tokens Now the question, how am I able to perform introspect from an external API server towards the F5 oauth server to validate that the provided JWT access token is still valid?1.1KViews0likes1CommentRequest and validate OAuth / OIDC tokens with APM
BIG-IP APM is able to request and validate OAuth2.0 and OpenID Connect tokens. It can act as Client, Resource Server and Authorization Server. In this article, I cover the use cases where APM acts as Resource Server (validating the tokens) and Client (requesting the tokens). 1. The tokens : Access Token: this is the Oauth2.0 token (access_token). It is used for Authorization and has to bevalidated by the Resource server. This Resource Server will contact the Authorization server for validation (Out of Path validation - External) Access Token can be either OPAQUE or JWT ID Token: this is the OpenID Token (id_token).It is used by the client onlyin order to know you use the resource owner. For instance, when you see you name and your picture on the top right corner of an app, this comes from the ID_Token. This token is not user/validated by the Resource Server ID Token is JWT only 2. OPAQUE vs JWT tokens : JWT: Decodable Encryptable Can be validated against a preconfigured JWKS in-box or externally OPAQUE: Not decodable (opaque) Proprietary format, might be any length, and must be unique Must be validated in out-of-path HTTP request to the originating provider (the Authorization Server) 3. Token validation : OAuth Scope agentis used to validate anAccess Token either against aninternalJSON web key set (JWKS) if the Access Token isJWTvia an APM provider configuration (Azure AD uses JWT only) orexternallyvia HTTPS if the Access Token isOpaque. JWKS is faster because we don't have an extra HTTP transaction. Oauth Scope agentis used when APM is RS and the request from the client (APM or mobile app) has a authorization bearer header. Either with Opaque (External)or JWT token (Internal). With Opaque token, if the RS needs more information about the user, it needs to request anOpenID Connect UserInfoby presenting theaccess_token to the AS. The opaque scope provides with several information but it depends of the AS. For Google, an OIDC userInfo is needed to get the First and Last names. 4. Token Request : Oauth Client agentis used to request theAccess token and id_tokenwhen APM is deployed asOauth Client. To do so, 2 grant types are available (Code and password) WithAuthorization code grant, the Client agentexchangesan Authorization code for an access_token code + id_token (if OIDC used). When the Oauth Client gets the access_token (and id_token), theOauth scope agent validatesthem.3.4KViews5likes3CommentsHow to trigger an OAuth discover using TMSH or REST API?
Hi all, I was just wondering how to trigger the discover process of an OAuth provider via TMSH or the REST API. I see a pull-config option in tmsh, but it doesn't appear to do anything?!? modify apm aaa oauth-provider provider_test pull-config Can anyone help? Regards, SimonSolved667Views0likes2Comments