Forum Discussion

eric_haupt1's avatar
eric_haupt1
Icon for Nimbostratus rankNimbostratus
Apr 01, 2019

Checking for APM variable existence

I need a conditional action to populate some APM variables into headers. These variables are going to be client-ip, Cert Issuer, Cert Subject, F5-Session ID,F5-Session start time, Cert email. If the user doesn't present a cert - they will still be permitted to pass through to the app, but I'll only send three headers for the info I have - client-ip, APM Session ID, APM session start.

If the user presents a cert, I'll send all five headers: client-ip, Session ID, Session start, Cert Issuer, Cert Subject, Cert email.

Now the trick is that I never want to send empty headers. I find that I can either send three all the time or send five with three empty but I'm having difficulty getting the variable conditional checking to work.

I've tried a few techniques but nothing seems to give me the behaviour I need. I know the variables are there for both access policy paths - but the non cert path should never have an email variable. I was hoping I could simply do something like:

if variable email exists - send all five else send three... looking for any suggestions here

when ACCESS_ACL_ALLOWED {
           if { [ACCESS::session exists session.custom.cert.email] } {
              [HTTP::header] insert "X-Forwarded-For" [IP:client_addr]
              [HTTP::header] insert "X-F5-SessionID" [ACCESS::session sid]
              [HTTP::header] insert "X-F5-Session-start" [ACCESS::session data get session.custom.start.time]
              [HTTP::header] insert "X-F5-Cert-Issuer" [ACCESS::session data get session.ssl.cert.issuer]
              [HTTP::header] insert "X-F5-Cert-Subject" [ACCESS::session data get session.ssl.cert.subject]
              [HTTP::header] insert "X-F5-Cert-Subject" [ACCESS::session data get session.custom.cert.email]
              return
              }
         else {     
              [HTTP::header] insert "X-Forwarded-For" [IP:client_addr]
              [HTTP::header] insert "X-F5-SessionID" [ACCESS::session sid]
              [HTTP::header] insert "X-F5-Session-start" [ACCESS::session data get session.custom.start.time]
              }
              }

2 Replies

  • Ok... I think this is it.

    when ACCESS_ACL_ALLOWED {
                set var_issuer [ACCESS::session data get session.ssl.cert.issuer]
                set var_subject [ACCESS::session data get session.ssl.cert.subject]
                set var_upn [ACCESS::session data get session.custom.cert.upn]
                set var_email [ACCESS::session data get session.custom.cert.email]
    
                HTTP::header insert "X-F5-Forwarded-For" [IP::client_addr]
                log local0. "X-F5-Forwarded-For [IP::client_addr]"
    
                HTTP::header insert "X-F5-Session-ID" [ACCESS::session sid]
                log local0. "X-F5-Session-ID [ACCESS::session sid]"
    
                HTTP::header insert "X-F5-Session-Start" [ACCESS::session data get session.custom.start.time]
                log local0. "X-F5-Session-Start [ACCESS::session data get session.custom.start.time]"
    
                if { [info exists var_issuer] && ($var_issuer ne "") } {
                        HTTP::header insert "X-F5-Cert-Issuer" [ACCESS::session data get session.ssl.cert.issuer]
                        log local0. "X-F5-Cert-Issuer [ACCESS::session data get session.ssl.cert.issuer]" }
                        else { return }
    
                if { [info exists var_subject] && ($var_subject ne "") } {
                        HTTP::header insert "X-F5-Cert-Subject" [ACCESS::session data get session.ssl.cert.subject]
                        log local0. "X-F5-Cert-Subject [ACCESS::session data get session.ssl.cert.subject]" }
                        else { return }
    
                if { [info exists var_upn] && ($var_upn ne "") } {
                        HTTP::header insert "X-F5-Cert-UPN" [ACCESS::session data get session.custom.cert.upn]
                        log local0. "X-F5-Cert-UPN [ACCESS::session data get session.custom.cert.upn]" }
                        else { return }
    
                if { [info exists var_email] && ($var_email ne "") } {
                        HTTP::header insert "X-F5-Cert-Email" [ACCESS::session data get session.custom.cert.email]
                        log local0. "X-F5-Cert-Email [ACCESS::session data get session.custom.cert.email]" }
                        else { return }
    }
    
  • Hi Eric,

    lets make a real life comparsion of what your iRule does.

    You have an entrance hall with a service desk where lots of customers are flowing in and you have a back office where your customer data is stored. Each time a customer visits your service desk your service desk operator is forced to walk several times into the backoffice to get the customer ID, their citizenship, their address and their prefered communication method independently.

    Does this makes sense? I guess it would be far more effective to store your customer data in such way, that a single walk into the back office would be sufficent to process a customer, isn't it?

    Your APM session variables and the

    ACCESS_ACL_ALLOWED
    iRule event are pretty much comparable to the scenario above. They are not mandatory working inline and may require TMM to perform connection parkings, which adds delay to the request and cost some CPU cycles.

    Because of this it would be much smarter to substitute a

    [list]
    item at the end of your APM policy (one time processing) and store the list into a custom session variable to make your header injection iRule (per request processing) much more efficent.

    APM Variable Assign for Certificate-Users:

    Variable Name:

    session.custom.sso_header_injection
    

    Expression:

    return [list 1 [mcget {session.user.sessionid}] [mcget {session.custom.start.time}] [mcget {session.ssl.cert.issuer}] [mcget {session.ssl.cert.subject}] [mcget {session.custom.cert.email}]]
    

    APM Variable Assign for non Certificate-Users:

    Variable Name:

    session.custom.sso_header_injection
    

    Expression:

    return [list 2 [mcget {session.user.sessionid}] [mcget {session.custom.start.time}]]
    

    Highly optimized iRule:

    when ACCESS_ACL_ALLOWED {
    
        log local0. "Injecting Header X-F5-Forwarded-For = [IP::client_addr]"
    
        HTTP::header insert "X-F5-Forwarded-For" [IP::client_addr]
    
        set sso_header_injection_list [ACCESS::session data get session.custom.sso_header_injection]
    
        log local0. "Retrieved header injection list = $sso_header_injection_list"
    
        if { [lindex $sso_header_injection_list 0] == 1 } then {
    
            log local0. "Certificate user detected..."
    
            log local0. "Injecting Header X-F5-SessionID = [lindex $sso_header_injection_list 1]"
            HTTP::header insert "X-F5-SessionID"      [lindex $sso_header_injection_list 1]
    
            log local0. "Injecting Header X-F5-Session-start = [lindex $sso_header_injection_list 2]"
            HTTP::header insert "X-F5-Session-start"  [lindex $sso_header_injection_list 2]
    
            log local0. "Injecting Header X-F5-Cert-Issuer = [lindex $sso_header_injection_list 3]"
            HTTP::header insert "X-F5-Cert-Issuer"    [lindex $sso_header_injection_list 3]
    
            log local0. "Injecting Header X-F5-Cert-Subject = [lindex $sso_header_injection_list 4]"
            HTTP::header insert "X-F5-Cert-Subject"   [lindex $sso_header_injection_list 4]
    
            log local0. "Injecting Header X-F5-Cert-Subject = [lindex $sso_header_injection_list 5]"
            HTTP::header insert "X-F5-Cert-Subject"   [lindex $sso_header_injection_list 5]
    
        } elseif { [lindex $sso_header_injection_list 0] == 2 } then {
    
            log local0. "Non-Certificate user detected..."
    
            log local0. "Injecting Header X-F5-SessionID = [lindex $sso_header_injection_list 1]"
            HTTP::header insert "X-F5-SessionID"      [lindex $sso_header_injection_list 1]
    
            log local0. "Injecting Header X-F5-Session-start = [lindex $sso_header_injection_list 2]"
            HTTP::header insert "X-F5-Session-start"  [lindex $sso_header_injection_list 2]
    
        }
    
    }
    

    Note: The iRule above requires only a single

    [ACCESS::session]
    command execution to retrieve the Operation mode and the APM based HTTP-Header values.

    Cheers, Kai