authentication
88 TopicsYubikey Authentication Modes and Azure AD integration via the APM
Introduction The Yubikey (https://www.yubico.com/) supports three major functions, authentication, signing and encryption. As far as authentication goes, it supports a list of the following mechanisms. OTP (one-time password) Yubikey OTP (Time based OTP) OATH HOTP (HMAC based OTP) FIDO U2F (Universal 2 nd Factor) FIDO2 PIV (Smartcard) Each of the above-mentioned protocols has its own set of requirements and is therefore not universally supported everywhere. OTP OTP is probably the simplest, with a one-time password being used, typically as the 2 nd factor. However, it is also the weakest, as it does not mitigate against MITM attacks. E.g., A fake site impersonating a legitimate site can trick the user into entering the OTP and subsequently forwards it to the real site. All Yubikey’s by default have manufacture assigned secrets registered with Yubico’s own validation servers. Yubico provides a tool that allows you to re-program the key, giving it a different secret. However, the new secret has to be uploaded to Yubico’s validation servers (https://upload.yubico.com/) otherwise OTP will stop working. Yubikey OTP integrates with a large number of services (e.g., Gmail, LastPass). When a service receives an OTP, it reaches out to Yubico for validation. In the case of Okta, the secrets can be uploaded directly into Okta and validation happens within Okta. FIDO U2F FIDO U2F or U2F for short, mitigates MITM. This method requires the user to register the authenticator (e.g., Yubikey) with the application (e.g., Gmail) first, during which a key pair is generated by the authenticator, and the public key is sent and stored on the application. Once the registration is complete, the user can then use the authenticator as the 2 nd factor. In the case of Gmail, once the user’s credentials are verified, the user touches the Yubikey for 2 nd factor. No code is entered by the user. FIDO2 FIDO2 enables passwordless authentication. Once the Yubikey is registered with an application (e.g., Azure Portal) for FIDO2 authentication, the user touches the Yubikey, optionally provides a PIN code for the key, logs straight in. – no username is entered FIDO2 is an evolution of U2F and is dependent upon WebAuthn (client API implemented within the browser) and CTAP2 (authenticator API that enables FIDO2-capable devices to interface to external/roaming authenticators over Bluetooth, USB or Near field communication (NFC)). Per FIDO Alliance (https://fidoalliance.org/fido2/fido2-web-authentication-webauthn/#:~:text=WebAuthn%20is%20currently%20supported%20in,Windows%2010%20and%20Android%20platforms), browser support for U2F and WebAuthn are shown below. PIV YubiKey can also present itself as a PIV smartcard that contains a client certificate. APM Integration There are a number of articles on DevCentral that cover programming the APM to receive the Yubikey OTP and then send it over to Yubico’s validation servers via a side band connection for OTP verification. My particular use case is to leverage an IDaaS (e.g., Azure AD) as an IDP and use the APM as the SP. My choice of integration is via OIDC, but SAML is an equally valid option. Since authentication is offloaded to Azure AD, both the OTP and FIDO2 passwordless authentication methods are now available. Azure AD does not support U2F. Azure AD and User Configuration OTP If Yubikey is used for OTP, Azure AD needs to have MFA enabled, a ‘Conditional Access’ policy is created to ‘Require multi-factor authentication’ for your selected apps. This process is documented by Microsoft (https://docs.microsoft.com/en-us/azure/active-directory/authentication/tutorial-enable-azure-mfa). The user must also add an authenticator app via self-registration (https://mysignins.microsoft.com/), be sure to click on the highlighted, this allows you to enrol the ‘Yubico Authenticator’ (https://www.yubico.com/products/services-software/download/yubico-authenticator/). The Yubico Authenticator works with the Yubikey to generate the OTP. Yubico argues that it is more secure as unlike a soft authenticator, the secrets are not saved within the authenticator itself, but rather in a secure element within the Yubikey. Note ‘Touch your Yubikey’, which is needed before an OTP is generated. The OTP method does not impose special requirements on the browsers, which means it works on any browsers, as well as on the APM Edge client, which leverages certain browser functions FIDO2 With FIDO2 based passwordless authentication, the ‘FIDO2 Security Key’ option within the Azure AD (e.g., under Security) has to be enabled first. Again, the user goes through self-registration (https://mysignins.microsoft.com/) prior to the Yubikey becoming available. I have tried different browsers on the Mac, the only browsers that work are Chrome and Edge. Milage may vary in Windows. If FIDO2 works, the highlighted option will appear. In the case of Azure AD, a PIN is required (configured over the self-registration process). Once it’s entered, the user logs in after touching the Yubikey. At this time, the latest (v7210) APM Edge client’s embedded browser for login does not work with FIDO2, likely due to WebAuthn not being supported. If the user uses a supported browser, passwordless authentication should work, after which a webtop is presented.4.2KViews1like2CommentsProblems with F5 Rseries and LDAPs for remote authentication
Good afternoon I'm having some problems getting remote authentication to work on my Rseries computer over LDAPS, when debugging I get the following error: Can't contact LDAP server: error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed (unable to get local issuer certificate) I have followed several guides and consulted different articles, but I can't find any of them which fields are mandatory and which aren't. My question is regarding the fields: Cipher String, TLS CA Certificate and TLS Key. Is it mandatory to fill in these fields? What happens if they are left empty? Best Regards53Views0likes1CommentHA Active Directory for F5 authentication
I have two f5 Big-IP wit LTM module in HA. I have configured Admin authentication in BIG-IP through Remote Active Directory and It works properly. The challenge is I have several synchronized AD servers and I would like to achieve HA in Big-IP authentication. I have created a pool with my AD servers with a custom LDAP monitor and It seems that works because all members look up in the pool. I also created a virtual server that listen in port 389 and use the AD server pool as default pool. However, when I set the host value to virtual server IP in system-->users-->authentication, all authentication attempts fail. Is required an special configuration in virtual server to make it work?55Views0likes2CommentsBigIP APM Oauth - set to 'Failed to perform curl: Failure when receiving data from the peer'
We've been dealing with a issue when an Oath token is sent to Azure for authentication using XXX.session.oauth.client.last.auth_redirect: login.windows.net/XXXXX/XXXX session.oauth.client.last.auth_resule 0 We are constantly seeing the error and causing out Oath Client to be denied. We are able to perform a "discover" in the Provider and able to "dig" to the Azure Enterprise.Our DNS Resolver is able to resolve DNS as per guide. Has anybody come across this and can point us in the right direction? The only way we can make is work is to change the APM policy to "fallback" Allow OAuthClientToAzureAD_act_oauth_client_ag: OAuth Client: failed for server '/DC-TEST/Azure_Oauth_Server' using 'authorization_code' grant type (client_id=XXXXXXXXXXXXXXXX), error: Failed to perform curl: Failure when receiving data from the peer Session variable 'session.oauth.client./DC-TEST/OAuthClientToAzureAD_act_oauth_client_ag.authresult' set to '0' Session variable 'session.oauth.client./DC-TEST/OAuthClientToAzureAD_act_oauth_client_ag.errMsg' set to 'Failed to perform curl: Failure when receiving data from the peer Session variable 'session.oauth.client.last.authresult' set to '0' OAuthClientToAzureAD_act_oauth_client_ag: OAuth: Request parameter 'client_secret=********'OAuthClientToAzureAD_act_oauth_client_ag: OAuth: Request parameter 'grant_type=authorization_code' OAuthClientToAzureAD_act_oauth_client_ag: OAuth: Request parameter 'redirect_uri=https://our.test.website.com/oauth/client/redirect OAuthClientToAzureAD_act_oauth_client_ag: OAuth: Request parameter 'code=********' OAuthClientToAzureAD_act_oauth_client_ag: OAuth Client: failed for server '/DC-TEST/Azure_Oauth_Server' using 'authorization_code' grant type (client_id=XXXXXXXXXXXXXXX), error: Failed to perform curl: Failure when receiving data from the peer If we change the Access Policy "fallback" to "Allow" the user is then allowed to reach the backend application but would have otherwise been denied. It seem during the Oauth Client process the token request is rejected Previously we were seeing the error below which we resolved by making sure the DNS resolver could resolve DNS correctly. OAuthClientToAzureAD_act_oauth_client_ag: OAuth Client: failed for server '/DC-TEST/AzureAD_Server' using 'authorization_code' grant type (client_id=d7b3f856-6053-462b-a8f3-c2820e2a4c6c), error: HTTP error 503, DNS lookup failed884Views0likes5CommentsAPM Full Step Up Authentication
Problem this snippet solves: By default, APM is not able to handle several authentication during a session. Once you are logged in, it’s finished, you can’t ask for authentication again. Since v12.1.0, we can see a new feature in EA called “Step-up Authentication” and the introduction of subroutines that is currently limited to ldap authentication or a confirm box. The irule and configuration below allow the administrator to define 2 levels of authentication based on URIs. The concept can be extended to have multiple authentication levels. This concept can be extended to define several Level of authentication. You can also change the element that trigger the additionnal authentication process. How to use this snippet: Installation irule To make it works, you need to install the irule on the Virtual Server that publish your application with APM authentication. datagroup You need to create a datagroup of string type. This dg must contains http path that need an additional authentication step. The dg is named loa3_uri in the irule example. access profile If you already have an existing access profile, you will need to modify it and include some additionnal configuration in your VPE. If you have no access profile, you can starts building your own based on the description we provide below. Scenarios 1) User try to reach strong uri after first authentication process In this scenario, the user first authenticate using a standard authentication mecanism. Once authenticated, if the user request content that is behing strong uris, the user restart an authentication process in the "Strong Auth" and "Already Auth" branch of the VPE. 2) User try to reach strong uri during the first authentication process If the user try to access a strong uri on its first attempt, he will need to complete the full authentication process. Then, he can access every part of the web application without any additional prompt. Special considerations Client certificate Authentication You may need to use Client certificate authentication as a primary factor or second factor. We highly recommend to use "SSl on-demand authentication" if you need it as primary factor. Client Certificate is not supported as a second factor, you need to use SSl on-demand authentication. WebSSO When first authentication has already been allowed and the user try to access a protected uri, the system will invite the user to complete the new authentication (second factor). This process will restart a webSSO action on the backend. Basic, NTLM and Kerberos webSSO have been tested with success. Configuring the Visual Policy Editor The printscreen below is a minimal Visual Policy Editor used to make Step up Authentication works properly : Strong Auth The strong Auth block is an "Empty Action" with two branch. The branch named "Strong" contains the following condition : expr { [mcget {session.server.landinguri}] starts_with "/strong" || [mcget {session.custom.last.strong}] == 1 } We check that the uri starts with strong (used in scenario 1) or if a custom variable is set to 1 (second scenario) Already Auth This is an empty action with two branch. The branch named "yes" contains the following expression : expr { [mcget {session.custom.last.authresult}] contains "true" } 2-factor Ending session.custom.last.authtype variable must be set to 1 session.policy.result.redirect.url must be changed. The session.server.landinguri contains the true origin uri. To set this variable, you must use the tcl script below : proc urldecode str { variable map variable alphanumeric a-zA-Z0-9 for {set i 0} {$i <= 256} {incr i} { set c [format %c $i] if {![string match \[$alphanumeric\] $c]} { set map($c) %[format %.2x $i] } } array set map { " " + \n %0d%0a } set str [string map [list + { } "\\" "\\\\"] $str] regsub -all -- {%([A-Fa-f0-9][A-Fa-f0-9])} $str {\\u00\1} str return [subst -novar -nocommand $str] } set decoded_uri [urldecode [string range [mcget {session.server.landinguri}] [expr { [string last = [mcget {session.server.landinguri}]] + 1 }] end]] return $decoded_uri Full strong Ending session.custom.last.authtype variable must be set to 1 Standard Ending session.custom.last.authtype variable must be set to 0 Session variables The following variables can be used in the 2-factor section of the Visual Policy Editor : session.custom.last.username session.custom.last.password Features 2-step authentication Retrieve username and password from first authentication Encrypt Session1 cookie to avoid session Hijacking External links Github : https://github.com/e-XpertSolutions/f5 Code : when RULE_INIT { # to be changed prior to any publishing set passphrase "hEuoYjmFUpB4PcpO3bUdQtLP4ic7jjm" } when HTTP_REQUEST { if { [HTTP::cookie exists MRHSession] and [ACCESS::session exists -state_allow -sid [HTTP::cookie MRHSession]] } { set strong_auth [ACCESS::session data get session.custom.last.authtype] if { [class match [HTTP::path] starts_with loa3_uri] and $strong_auth == 0 } { HTTP::cookie encrypt "MRHSession" $passphrase HTTP::respond 302 noserver "Location" "/strong?return_url=[URI::encode [HTTP::uri]]" "Cache-Control" "no-cache, must-revalidate" Set-Cookie "MRHSession=deleted;expires=Thu, 01-Jan-1970 00:00:10 GMT;path=/" Set-Cookie "LastMRH_Session=deleted;expires=Thu, 01-Jan-1970 00:00:10 GMT;path=/" Set-Cookie "Session1=[HTTP::cookie MRHSession];path=/" } } } when ACCESS_SESSION_STARTED { # decrypt Session1 cookie value set decrypted [HTTP::cookie decrypt "Session1" $passphrase] if { [HTTP::cookie exists Session1] and [ACCESS::session exists -state_allow -sid $decrypted] } { ## section : retrieve session variables from the first session ACCESS::session data set session.custom.last.username [ACCESS::session data get session.logon.last.username -sid $decrypted] ACCESS::session data set session.custom.last.password [ACCESS::session data get session.logon.last.password -sid $decrypted] ## End section ACCESS::session data set session.custom.last.authresult "true" # remove the first created session during standard authentication to avoid multiple active sessions ACCESS::session remove -sid $decrypted } elseif { [class match [HTTP::path] starts_with loa3_uri] } { ACCESS::session data set session.custom.last.strong 1 } } Tested this on version: 11.51.3KViews0likes7CommentsForm Based Authentication with external SOAP web services
Problem this snippet solves: 1- You need to authenticate users against an external authentication system relying on SOAP calls. 2- The session identifier must be provided by an external third party system. How to use this snippet: Installation Files You need to upload an html login page using ifiles. You need to upload the SOAP body of the external web service using ifiles. irule You need to install the irule on your Virtual Server you need to protect. Variables set static::holdtime 3600 # session timeout set static::login_url "/login" # login url set static::sideband_vs "VS_EXTERNAL_AUTH_PROVIDER" # Virtual Server that publish the web service Features Version 1.0 Form based login (provided by a custom ifile) Authentication against an external SOAP web service Manage Session timeout Backlog Improve logging Allow 2-factor authentication (Challenge) Encrypt Session cookie Provide internal mecanism to generate a session cookie accept Basic Authentication External links Github : https://github.com/e-XpertSolutions/f5 Code : when RULE_INIT { set static::holdtime 3600 set static::login_url "/login" set static::sideband_vs "VS_EXTERNAL_AUTH_PROVIDER" } when HTTP_REQUEST { if { [HTTP::cookie exists SessionCook] and [table lookup -subtable "active_sessions" [HTTP::cookie SessionCook]] != "" } { return } else { if { [HTTP::path] eq $static::login_url } { if { [HTTP::method] eq "POST" } { if {[HTTP::header "Content-Length"] ne "" && [HTTP::header "Content-Length"] <= 1048576}{ set content_length [HTTP::header "Content-Length"] } else { set content_length 1048576 } if { $content_length > 0} { HTTP::collect $content_length } } else { HTTP::respond 200 content [ifile get login.html] "Cache-Control" "no-cache, must-revalidate" "Content-Type" "text/html" } } else { HTTP::respond 302 noserver "Location" $static::login_url "Cache-Control" "no-cache, must-revalidate" Set-Cookie "SessionCook=$result;domain=[HTTP::host];path=/" } } } when HTTP_REQUEST_DATA { set payload [HTTP::payload] set username "" set password "" regexp {Login1\%3AtxtUserName\=(.*)\&Login1\%3AtxtPassword\=(.*)\&Login1\%3AbtnSubmit\=(.*)} $payload -> username password garbage if {[catch {connect -timeout 1000 -idle 30 -status conn_status $static::sideband_vs} conn_id] == 0 && $conn_id ne ""}{ log local0. "Connect returns: $conn_id and conn status: $conn_status" } else { log local0. "Connection could not be established to sideband_virtual_server" } set content [subst -nocommands -nobackslashes [ifile get soap_body]] set length [string length $content] set data "POST /apppath/webservicename.asmx HTTP/1.1\r\nHost: www.hostname.com\r\nContent-Type: text/xml; charset=utf-8\r\nContent-Length: $length\r\nSOAPAction: http://schemas.microsoft.com/sqlserver/2004/SOAP\r\n\r\n$content" set send_bytes [send -timeout 1000 -status send_status $conn_id $data] set recv_data [recv -timeout 1000 $conn_id] # parse response to retrieve the authentication result, it gives 0 if authentication failed or a session_id if it succeed regexp { (.*) (.*)} $recv_data -> result garbage unset content unset length unset data unset recv_data close $conn_id # add a custom alert notification to the login page if { $result == 0 } { set alert " Invalid credentials. " HTTP::respond 200 content [subst -nocommands -nobackslashes [ifile get login.html]] "Cache-Control" "no-cache, must-revalidate" "Content-Type" "text/html" Set-Cookie "SessionCook=deleted;expires=Thu, 01-Jan-1970 00:00:10 GMT;domain=[HTTP::host];path=/" } else { HTTP::respond 302 noserver "Location" "/" "Cache-Control" "no-cache, must-revalidate" Set-Cookie "SessionCook=$result;domain=[HTTP::host];path=/" # save the cookie value in a cache for fast checking table add -subtable "active_sessions" $result $username indef $static::holdtime } } Tested this on version: 11.5458Views0likes1CommentAPM HTTP auth - POST
with APM, I need to build the following flow - user logs on APM logon page, credentials are validated with LDAP auth - those credentials are sent to an existing auth webserver, with a POST (HTTP auth) - that auth webserver replies with the same username (as the one sent in the form) if authorized Question: can we use session variable in the "Successful Logon detection match value" field, as we look for "specific string in response"? Anyone successfully implemented that?177Views0likes0CommentsNTLM Machine Account Issues - APM
Good afternoon - I am hoping someone can point me in the right direction. I'm trying to use the iApp to deploy RDP Gateway using APM (using this template - ). Part of the config is to create a new NTLM Machine account. I had no issues creating the account - and the iApp deployment went swimmingly well. I also verified that the machine account showed up in AD as a computer account. However, I am seeing these errors in the APM logs: May 15 17:40:32 f5lab debug nlad[6379]: 01620000:7: <0x56900b70> nlclnt[2a8e2c794]: is now initializing. May 15 17:40:32 f5lab debug nlad[6379]: 01620000:7: <0x56900b70> NLAD_TRACE: cli_full_connection(output_cli = (nil), my_name = "F5LAB", dest_host = "domaincontroller.domain.local", port = 445, service = "IPC$", service_type = "IPC", user = "F5LAB$", domain = "DOMAIN") May 15 17:40:32 f5lab debug nlad[6379]: 01620000:7: <0x56900b70> NLAD_TRACE: cli_full_connection(output_cli = (nil)) = 0xC000006D May 15 17:40:32 f5lab err nlad[6379]: 01620000:3: <0x56900b70> nlclnt[2a8e2c794] init: Error [0xc000006d,NT_STATUS_LOGON_FAILURE] connecting to DC 10.11.12.13 I also cannot renew the NTLM account password from the GUI as I get this error: Could not connect to domain domain controller of realm 'domain.local' machine account update for 'f5lab' failed: Preauthentication failed, principal name: f5lab@domain.local. Invalid user credentials. (-1765328360) I'm running on 12.1.3.4 and have tried the following: Recreated the NTLM account, multiple times. I know I have permissions as the account does show up in AD, and I do have domain admin level permissions Restarted the eca service (bigstart restart eca) Restarted the nlad service (bigstart restart nlad) Restarted the F5 appliance itself. Verified that the DNS settings are configured properly. The F5 is able to resolve the domain controller IP from the alias. No firewall exists between this F5 and the domain controller. Has anyone seen this and if so - can anyone point me in the right direction? I thought I'd try here before opening a support ticket with F5.546Views0likes4CommentsSubsequent Form Based SSO
Problem this snippet solves: After performing a successful APM Form Based SSO it can happen that the backend website will expire the user session while the APM session is still active. When this happens, the user will see the logon page of the backend website and needs to login again. This code snippet will try to detect that the user is being redirected to the backend website login page and will perform a Form Based SSO again by using the credentials from the active APM session. How to use this snippet: When using this code snippet, make sure you set the below shown variables to match your environment. set static::start_uri set static::form_action You should also use the Variable Assign agent in the VPE to set the APM session variable session.custom.form_based.password with the users password. This password will be used to perform the subsequent Form Based SSO. Use the following custom expression: return [mcget -secure {session.logon.last.password}] . Code : when RULE_INIT { set static::start_uri "login.html" set static::form_action "/F5/form_based_login/login.php" set static::form_html { Your browser does not support JavaScript, press the Continue button once to proceed. } set static::form_html [string map "form_action $static::form_action" $static::form_html] } when HTTP_REQUEST { if { [HTTP::cookie exists MRHSession] and [ACCESS::session exists -state_allow -sid [HTTP::cookie MRHSession]] } { set active_session 1 if { [HTTP::method] equals "POST" && [HTTP::uri] equals $static::form_action } { set collect_length 2048 if { [HTTP::header Content-Length] eq "" } { set collect_length $collect_length } elseif { [HTTP::header Content-Length] == 0 } { unset collect_length } elseif { [HTTP::header Content-Length] > $collect_length } { set collect_length $collect_length } else { set collect_length [HTTP::header Content-Length] } if { [info exists collect_length] } { HTTP::collect $collect_length } } } } when HTTP_REQUEST_DATA { # the session.custom.form_based.password variable needs to be set via a variable assign agent in the VPE. set username [ACCESS::session data get session.logon.last.username] set password [ACCESS::session data get session.custom.form_based.password] HTTP::payload replace 0 [HTTP::payload length] "username=$username&password=$password" } when HTTP_RESPONSE { if { [info exists active_session] } { if { [HTTP::header "Location"] equals $static::start_uri } { if { [ACCESS::session data get session.custom.first_redirect] == 1 } { # this is the subsequent redirect which is not covered by APM Form Based SSO HTTP::respond 200 content $static::form_html } else { # this is the initial redirect which is covered by APM Form Based SSO ACCESS::session data set session.custom.first_redirect 1 } } unset active_session } } Tested this on version: 13.0356Views0likes2Comments