jwt
16 Topicsoauth server generated jwt token problem
Hi all, We have a customer try to do oauth with a dovecot server, they have the following problems using the f5 as a oauth server: The "typ" jwt header is missing, this should be set to "JWT". F5 set the JWT token nbf (not valid before) to some minutes in the past, this breaks dovecot auth. Customer want to use the following oauth features, are these supported? https://openid.net/specs/openid-connect-frontchannel-1_0.html https://openid.net/specs/openid-connect-backchannel-1_0.html Do you know how the above could be customized in f5 to set to values the dovecot would accept? Thank you for any hint. Peter1.2KViews3likes5CommentsJSON Web Token (JWT) Parser
Problem this snippet solves: This feature is now native in v13.1 and it is strongly recommended you implement the native solution instead. This code is left only as an example for future use cases, it should not be used for JWT handling because there is no signature validation. This code parses a JWT (JSON Web Token) received by a Big-IP acting as an OAuth client and creates session variables for the JSON parameters in the header and payload. Example use cases might include Azure AD B2C or Azure AD Enterprise integration. This iRule does not perform signature validation. Code from the "Parse and Set Session Variables" section down could be easily harvested for other JSON parsing use cases that do not need the JWT decoding. How to use this snippet: Attach this iRule to the virtual server receiving the JWT that is configured for OAuth. Inside the VPE after the OAuth Client agent add an iRule agent with id jwt-parse. This iRule will set several variables including: session.oauth.jwt.last.header session.oauth.jwt.last.payload session.oauth.jwt.last.signature In addition it will create a session variable for each parameter in the header and payload in the following syntax. session.oauth.jwt.header.last.* session.oauth.jwt.payload.last.* You can then call these session variables elsewhere. Code : when ACCESS_POLICY_AGENT_EVENT { if { [ACCESS::policy agent_id] eq "jwt-parse" } { #log local0. "JWT-Parse: Started" #Get the JWT set jwt [ACCESS::session data get -secure session.oauth.client.last.id_token] #log local0. "JWT-Parse: JWT Received - jwt is $jwt" #Separate the header, payload, and signature set jwt_header [getfield $jwt "." 1] ACCESS::session data set session.oauth.jwt.last.header $jwt_header #log local0. "JWT-Parse: Header extracted - jwt_header and session.oauth.jwt.last.header are $jwt_header" set jwt_payload [getfield $jwt "." 2] ACCESS::session data set session.oauth.jwt.last.payload $jwt_payload #log local0. "JWT-Parse: Payload extracted - jwt_payload and session.oauth.jwt.last.payload are $jwt_payload" set jwt_signature [getfield $jwt "." 3] ACCESS::session data set session.oauth.jwt.last.signature $jwt_signature #log local0. "JWT-Parse: Signature extracted - jwt_signature and session.oauth.jwt.last.signature are $jwt_signature" #Base 64 decode the header and payload #Fix encoding issues in header set jwt_header_modified $jwt_header set tail [string length $jwt_header_modified] if {$tail % 4 == 2} { append jwt_header_modified {==} } elseif {$tail % 4 == 3} { append jwt_header_modified {=} } #log local0. "JWT-Parse: Header encoding fixes complete - jwt_header_modified is $jwt_header_modified" #Fix encoding issues in payload set jwt_payload_modified $jwt_payload set tail [string length $jwt_payload_modified] if {$tail % 4 == 2} { append jwt_payload_modified {==} } elseif {$tail % 4 == 3} { append jwt_payload_modified {=} } #log local0. "JWT-Parse: Payload encoding fixes complete - jwt_payload_modified is $jwt_payload_modified" #Base64 decode set jwt_header_modified [b64decode $jwt_header_modified] #log local0. "JWT-Parse: Header Base 64 decoded - jwt_header_modified is $jwt_header_modified" set jwt_payload_modified [b64decode $jwt_payload_modified] #log local0. "JWT-Parse: Payload Base 64 decoded - jwt_payload_modified is $jwt_payload_modified" #Parse and Set Session Variables #Remove JSON characters set jwt_header_modified [string map {\{ {} \} {} \[ {} \] {} \" {}} $jwt_header_modified] #log local0. "JWT-Parse: Header JSON Characters removed - jwt_header_modified is $jwt_header_modified" set jwt_payload_modified [string map {\{ {} \} {} \[ {} \] {} \" {}} $jwt_payload_modified] #log local0. "JWT-Parse: Payload JSON Characters removed - jwt_payload_modified is $jwt_payload_modified" #Split into field/value pairs set jwt_header_modified [split $jwt_header_modified ,] #log local0. "JWT-Parse: Header Fields split - jwt_header_modified is $jwt_header_modified" set jwt_payload_modified [split $jwt_payload_modified ,] #log local0. "JWT-Parse: Payload Fields split - jwt_payload_modified is $jwt_payload_modified" #Set APM session variables for each header parameter foreach parameter $jwt_header_modified { set variable_name [getfield $parameter ":" 1] set variable_value [getfield $parameter ":" 2] ACCESS::session data set session.oauth.jwt.header.last.$variable_name $variable_value #log local0. "JWT-Parse: Header session variable set - session.oauth.jwt.header.last.$variable_name is $variable_value" } #Set APM session variables for each payload parameter foreach parameter $jwt_payload_modified { set variable_name [getfield $parameter ":" 1] set variable_value [getfield $parameter ":" 2] ACCESS::session data set session.oauth.jwt.payload.last.$variable_name $variable_value #log local0. "JWT-Parse: Payload session variable set - session.oauth.jwt.payload.last.$variable_name is $variable_value" } } } Tested this on version: 13.03.5KViews2likes14Comments3 Ways to Connect BIG-IP to Istio
Istio, a service mesh, uses “zero trust” to authenticate services.We’ll look at 3 ways to connect BIG-IP to Istio. 1. TCP The first method that we will use will be TCP.This will allow the BIG-IP to passthrough client traffic to Istio’s Ingress Gateway. 2. Mutual TLS (mTLS) The second method is to use the Client Certificate Constrained Delegation (C3D) feature of BIG-IP to authenticate client connections via mTLS and then generate a new client certificate (with similar attributes to the original) and use that newly minted certificate to authenticate to Istio. This second example is useful for scenarios where you are unable to install a trusted (externally CA signed) certificate into Istio (corporate policy prohibits it) and/or you want to establish a TLS DMZ.Despite the connection using mTLS the BIG-IP can inspect the traffic (i.e. log to Splunk), apply policy (i.e. insert XFF headers, WAF protection), etc… 3. JSON Web Tokens (JWT) Istio can use JWT tokens to authenticate users, but not all enterprise systems speak JWT.Using BIG-IP Access Policy Manager (APM) we can create an access policy that performs Single-Sign On (SSO) with an OAuth bearer token (JWT).This enables us to authenticate a client with username / password and convert the identity into a JWT token that is understood by Istio. Video Please These 3 methods are discussed and demo’d in the following YouTube video. Thanks for reading/watching!2.2KViews2likes2CommentsUsing 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"611Views2likes2CommentsAPM JWT Multiple Providers NOT WORKING
Dear F5 community, Using F5 APM 16.1.3 (as an oauth resource server) I am trying to implement a per-request policy that will verify the signature of JWT tokens sent by the client. These JWT tokens can be issued from two differents issuer (Azure AD or STS). I am able to verify JWT tokens for each provider seperatly using a dedicated "JWT provider" with only one Provider attached. When using 2 providers as follow I got following error message: WWW-Authenticate:Bearer error="invalid_token",error_description="Issuer Mismatch : Claim issuer= https://sts.windows.net/ Provider issuer=https://login.microsoftonline.com/v2.0" Based on F5 doc below, the built-in object supports having multiple JWT providers https://clouddocs.f5.com/cli/tmsh-reference/v15/modules/apm/apm_oauth_jwt-provider-list.html Configuration is pretty simple: - 1 Access Policy with "Allow" all ending - 1 Per-Request Policy with "OAuth Scope" set to "Internal" with the "jwt-allowed-providers-list" I guess It is most likely a bug. Anyone was able to make it work with multiple JWT providers ? I can workaround this by parsing the JWT payload, then determining the issuer and based on the issuer make two branches in the VPE: - first branch with the "oauth scope A" that will validate the token using JWT-Provider-A - second branch with the "oauth scope B" that will validate the token using JWT-Provider-B Thanks2.1KViews1like5CommentsConfiguring NGINX API micro-gateway to support Open Banking's Advanced FAPI security profile
Introduction In my last article, Integrating NGINX Controller API Management with PingFederate to secure financial services API transactions, we have seen how to configure NGINX Controller to perform basic JWT authorization against PingFederate, configured as OIDC IdP / OAuth Autorization Server. One weakness of the basic JWT authentication mechanism is the lack of context: anyone presenting a valid JWT will be allowed to performed the actions granted by the token, even if the sender is not the original OAuth client that was issued the token. This opens an avenue for attackers to use JWTs stollen from their rightful owners. Ideally, a mechanism of restricting the usage of the JWT to their original requestor is needed and this type of protection is specifically required for API calls presenting the highest risk, such as financial API calls. For example, Financial-grade API (FAPI) Security Profile 1.0 - Part 2: Advanced (Read and Write API Security Profile) specifies that: Authorization server: shall only issue sender-constrained access tokens; shall support MTLS as mechanism for constraining the legitimate senders of access tokens; Uncertainty of resource server handling of access tokens The protected resources that conform to this document shall not accept a bearer access token. They shall only support sender-constrained access tokens via MTLS. It is therefore useful to examine the configuration of NGINX, in its micro-gateway deployment mode, needed to perform the function of a resource server in cases requiring the Advanced FAPI security profile. Setup A high-level diagram of the lab environment used to demonstrate this setup is found below: The roles performed by each network element are described below: Authentication and API flow The workflow is very similar with the one described in my last article, with the differences highlighted here in bold: The user logs into the Third Party Provider application ("client") and creates a new funds transfer The TPP application redirects the user to the OAuth Authorization Server / OIDC IdP - PingFederate The user provides its credentials to PingFederate and gets access to the consent management screen where the required "payments" scope will be listed If the user agrees to give consent to the TPP client to make payments out of his/her account, PingFederate will generate an authorization code (and an ID Token) and redirect the user to the TPP client The TPP client opens an MTLS connection to the IdP, authenticates itself with a client certificate, exchanges the authorization code for a user-constrained access token and attaches it as a bearer token to the /domestic-payments call sent to the API gateway over an MTLS session authenticated with the same client certificate The API Gateway terminates the MTLS session and obtains the client certificate, authenticates the access token by downloading the JSON Web Keys from PingFederate, checks the hashed client certificate matches the value found in the token and grants conditional access to the backend application The Kubernetes Ingress receives the API call and performs WAF security checks via NGINX App Protect The API call is forwarded to the backend server pod Examining the differences between the workflows, it becomes apparent the extra actions NGINX API micro-gateway has to perform to support this advanced security use case are MTLS termination and client certificate hash verification. NGINX API micro-gateway configuration The full configuration is available on DevCentral's Code Share: Configure NGINX microgateway for MTLS termination and client certificate hash verification I will highlight below the most relevant parts of the configuration. MTLS termination server { server_name api.bank.f5lab; listen 443 ssl; ssl_certificate /etc/nginx/f5lab.crt; ssl_certificate_key /etc/nginx/f5lab.key; ssl_session_cache off; ssl_prefer_server_ciphers off; ssl_client_certificate /etc/nginx/updated_ca.crt; ssl_verify_client on; ssl_verify_depth 10; A detailed explanation of each of these commands can be found in the ngx_http_ssl_module user guide. JWT client certificate hash verification To compute and validate the client certificate hash, we will use an njs script (more information on njs scripting language and installation process can be found here). The njs script used (named "x5t.js" in our case) is shown below: function validate(r) { var clientThumbprint = require("crypto") .createHash("sha256") .update(Buffer.from(r.variables.ssl_client_raw_cert.replace(/(\n|----|-BEGIN|-END| CERTIFICATE-)/gm, ''), 'base64')) .digest("base64url"); return clientThumbprint === r.variables.jwt_cnf_fingerprint ? '1' : '0'; } export default { validate } Importing the "x5t.js" script in the main nginx configuration is done by: js_import /etc/nginx/x5t.js; We are populating the value of variable $jwt_cnf_fingerprint (available to the njs script via "r.variables.jwt_cnf_fingerprint") by extracting the 'x5t#S256' value from JWT: auth_jwt_claim_set $jwt_cnf_fingerprint 'cnf' 'x5t#S256'; The "validate" function of "x5t.js" will the compare the value of $jwt_cnf_fingerprint variable extracted from JWT with the computed SHA256 hash of the client certificate and set the validation result in the $thumbprint_match variable. js_set $thumbprint_match x5t.validate; Lastly, we will make a decision to accept or block client's access based on the validation result: if ($thumbprint_match != 1) { return 403 'Access denied because client SSL certificate thumbprint does not match jwt_cnf_fingerprint'; } Conclusion Supporting MTLS termination and client certificate hash validation against sender-constrained JWTs issued by Authorization Servers such as PingFederate, enables NGINX API micro-gateway to support Open Banking's Advanced FAPI security profile. Resources The UDF lab environment used to build this configuration can be found here.1.9KViews1like0CommentsIn the oauth profile unable to select JWT keys
2 keys are created in the JWT keys configuration, however when trying to configure the Oauth profile, select checkbox Support JWT Token the JWT Primary Key select box is empty. https://techdocs.f5.com/en-us/bigip-15-0-0/big-ip-access-policy-manager-oauth-configuration/using-apm-as-an-oauth-2-server.html Key are available here in same partition Access››Federation:JSON Web Token:Key Configuration Within the Oauth profile unable to select the keys Access››Federation:OAuth Authorization Server:OAuth Profile Someone got any idea why this is occurring?706Views1like3Comments