Forum Discussion

mike_aws_119486's avatar
mike_aws_119486
Icon for Nimbostratus rankNimbostratus
Jan 14, 2014

Rename default MRHsession cookie?

I have a requirement to have APM Edge (at the Edge of the network facing internet) connecting to an APM appliance within the internal network which is providing Portal Access/SSO to apps.

 

I've configured APM Edge for 'Web Access' (as we don't want/need it rewriting stuff' and do strong authentication to RSA SecurID. I've configured the inside APM for 'Portal Access' (accessing multiple internal apps with URL rewriting) with AD authentication and SSO.

 

This doesn't work and I get an error about invalid session ID, I suspect what is happening is:

 

APM Edge issues MRHsession cookie for its session ID (e.g. ABC123) APM Edge forwards web connection to the Portal hosted by internal APM Internal APM issues MRHsession cookier for its session ID (e.g. XYZ987) overwriting original Next connection to APM Edge is rejected as MRHsession cookie contains an invalid session ID

 

Is there a way to use non default session cookie names such that the session cookies from the two APM platforms don't conflict?

 

For info the 'inside' F5 APM is replacing a very old Juniper SA for which this works ok (e.g. APM Edge forwards connection to portal on Juniper SA which does URL rewriting/App Publishing).

 

So technically it should be possible to do if only the internal APM didn't overwrite the external APM session cookie!

 

Many thanks in advance!

 

10 Replies

  • Well, architectural issues aside, the only way I can think of doing this is to use an iRule on your external F5 to rewrite the cookie name from the internal F5 for delivery to the client, and then rewrite it for delivery back to the internal F5. You could probably use a stream expression, also.

     

  • Thanks, from an architectural perspective think of this as two completely seperate networks.

     

    Network A wants to present a bunch of Apps to Network B so uses F5 APM to authenticate users to AD and present a portal to Network B with URL rewriting/SSO.

     

    Network B wants to present the portal to external users over the internet and happens to also use F5 APM in their internet DMZ with RSA Auth.

     

    Network A has no direct connection to the internet, Network B has no direct connection to the backend apps.

     

    With different products it works (F5 APM in Network B + Juniper SA in Network A) the challenge is with both being F5.

     

    I've tried writing an iRule today to capture session information but didn't seem to work. I did think some kind of rewrite of the backend cookies (but not the backend content) would be the solution but not entirely sure how to re-write the backend cookie?

     

  • If I may add, stacked APMs in an "air gap" configuration like this can be challenging. When you first connect to an APM VIP, you get that initial 302 redirect to /my.policy to start the session (and get the session cookie). So it's not just the cookies that are getting confused, but when you start an APM session on the external APM, then transit to the internal APM, that internal APM's initial 302 redirect will confuse the external APM. The way I've generally handled this is to:

     

    1. Use an iRule on the external APM to "manage and store" the session cookies from the internal APM. So when the internal APM sends its cookies, I store those in the external APM's user session and remove them from the stream. When a request comes in I remove the external APM's cookies from the stream and replace with the internal APM's cookies.

       

    2. Put the internal APM into "clientless-mode". This has the effect of disabling the initial 302 redirect to /my.policy, but also prohibits "blocking" mechanisms like logon forms, message boxes, and webtops. You can do pretty much anything else in the visual policy and all SSO should work. To get user credentials to the internal APM (in the absence of an internal logon form), I would request them on the external APM and send them as HTTP headers in the stream.

       

    Here's a version of the iRule used on the external APM:

     

    when HTTP_REQUEST_RELEASE {
         This event fires at the end of the access policy (just before releasing to the internal LTM) and
         blocks external APM session cookies from reaching the internal APM
        foreach externalcookie {"MRHSession" "LastMRH_Session" "F5_ST"} {
            HTTP::cookie remove $externalcookie
        }
    
         When initiating an APM policy, it sets a series of client session cookies. In this case the external
         APM captures the internal APM policy session cookies, stores them in the external session cache as 
         session variables (so that the internal session is "linked" to the external session), and removes
         them from the wire to the client. When the client makes a new request, the internal session tokens
         are retrieved from the external session cache and replayed to the internal APM as if the client
         sent them. This code section extracts the internal session tokens from the external session cache
         and inserts them as cookies to the internal APM.
        set cookielist [list]
        if { [ACCESS::session data get session.custom.internalMRH] ne "" } {
            lappend cookielist "MRHSession=[ACCESS::session data get session.custom.internalMRH];"
        }
        if { [ACCESS::session data get session.custom.internalLMRH] ne "" } {
            lappend cookielist "LastMRH_Session=[ACCESS::session data get session.custom.internalLMRH];"
        }
        if { [ACCESS::session data get session.custom.internalF5ST] ne "" } {
            lappend cookielist "F5_ST=[ACCESS::session data get session.custom.internalF5ST];"
        }
    
         reformat incoming Cookie header to include all of the locally managed cookies in one Cookie header
        set cookiehdr [HTTP::header "Cookie"]
        HTTP::header remove "Cookie"
        HTTP::header insert "Cookie" "[join $cookielist] $cookiehdr"
    
         The clientless-mode header tells the internal APM to create the session without the normal series of
         redirects. The remaining headers are used to transmit authenticated user data to the internal APM.
        HTTP::header replace "clientless-mode" 1
    
         This is the data that will be passing to the internal APM - define HTTP headers and values here
        HTTP::header replace AGUSER "joe.user"
        HTTP::header replace AGDOMAIN "CHARLIE"
    }
    when HTTP_RESPONSE {
         The internal APM's session initiation process sends a series of Set-Cookie headers. This code section
         captures those Set-Cookies, stores them in the external session cache, and removes them from the wire to the client.
        if { [HTTP::cookie exists "MRHSession"] } {
            ACCESS::session data set session.custom.internalMRH [HTTP::cookie value "MRHSession"]
            HTTP::cookie remove "MRHSession"
        }
        if { [HTTP::cookie exists "LastMRH_Session"] } {
            ACCESS::session data set session.custom.internalLMRH [HTTP::cookie value "LastMRH_Session"]
            HTTP::cookie remove "LastMRH_Session"
        }
        if { [HTTP::cookie exists "F5_ST"] } {
            ACCESS::session data set session.custom.internalF5ST [HTTP::cookie value "F5_ST"]
            HTTP::cookie remove "F5_ST"
        }
    }

    Then on the internal APM VIP, something like this:

     

    when CLIENT_ACCEPTED {
         This command MUST be here
        ACCESS::restrict_irule_events disable 
    }
    when ACCESS_SESSION_STARTED {
         The authenticated user data is being transmitted from the external APM via HTTP headers. This section
         extracts those values and inserts them back into APM access policy session variables for use by the
         server side authentication process.
        if { [HTTP::header AGUSER] ne "" } {
            ACCESS::session data set session.logon.last.username [string trim [HTTP::header AGUSER]]
        }
    }

    It would conceivably be possible to not set clientless-mode on the internal APM VIP, and then handle all of the redirects and cookies in the external APM VIP's iRule, but that would be even less intuitive, and require not just changing the session cookies but also changing the redirects and internal APM URI patterns.

     

    • Marvin's avatar
      Marvin
      Icon for Cirrocumulus rankCirrocumulus

      Hi Kevin, great Irule seems to work when having portal mode because all URLs are rewritten, when using LTM+APM mode (as you already mentioned) we need to map and redirect or rewrite all embedded F5 urls so they wont be processed by the external F5. We tried to redirect /my.policy to /policy and then at request release to rewrite it back to /my.policy and seems to work however the cookie header is empty when using your Irule. Do you have any guidance on how we could perform this correctly in APM+LTM mode with 2 F5 APM chained?

      • Marvin's avatar
        Marvin
        Icon for Cirrocumulus rankCirrocumulus

        we cant modify the internal F5 so it needs to be fixed on the external F5

  • Kevin,

    Many thanks for your reply.

    First for the dumb question, do I need to set the internal APM to clientless-mode in some way or is that already done in the iRule?

    From what I read when APM is in clientless-mode you can't have a logon page....this presents a challenge as the internal APM currently has a policy which has:

    Logon Page (Heavily customised with warnings/info etc) > AD Auth > SSO Mapping > Full Resource Access (Portal Access).

    The APM at the edge has no access to the AD for auth and does RSA SecurID auth (e.g. users have to authenticate twice, once to RSA at the edge, then get the customised logon page with AD auth on the internal APM).

    Is what you are suggesting to construct the customised logon page on the edge device to capture the AD credentials which would then be passed to the backend APM policy to authenticate?

    Ideally I don't want to have to use clientless mode on the internal APM as then I could potentially use the VS/APM policy as is presented to internal users.

    HAving said that this is what i tried:

    Added a "Logon Page" to the end of the Edge APM policy to capture username/password Ammended the front end iRule to include:

     This is the data that will be passing to the internal APM - define HTTP headers and values here
    set apmsessionuser [ACCESS::session data get "session.logon.last.username"] 
    set apmsessionpass [ACCESS::session data get "session.logon.last.password"] 
    HTTP::header replace AGUSER $apmsessionuser
    HTTP::header replace AGPASS $apmsessionpass
    

    Removed the Logon page from the internal APM policy Ammended the internal iRule to include:

     The authenticated user data is being transmitted from the external APM via HTTP headers. This section
     extracts those values and inserts them back into APM access policy session variables for use by the
     server side authentication process.
    if { [HTTP::header AGUSER] ne "" } {
        ACCESS::session data set session.logon.last.username [string trim [HTTP::header AGUSER]]
    if { [HTTP::header AGPASS] ne "" } {
        ACCESS::session data set session.logon.last.password [string trim [HTTP::header AGPASS]]
    }
    }
    

    However I get is "Your session is finished. Logged out succesfully".

    If I look at the list of sessions on the back-end it is correctly showing the username captured in that second logon page so that is coming across, but in the Access report the username deoesn't show and the report is as follows:

    2014-01-16 18:16:09 Following rule 'fallback' from item 'Start' to item 'AD Auth' Common

    2014-01-16 18:16:09 AD agent: ENTER Function executeInstance Common

    2014-01-16 18:16:09 AD module: ENTER Function authenticateUser Common

    2014-01-16 18:16:09 AD module: authentication with '' failed: empty password detected (-1) Common

    2014-01-16 18:16:09 AD module: authenticate(): empty password detected (-1) Common

    2014-01-16 18:16:09 AD module: LEAVE Function authenticateUser Common

    2014-01-16 18:16:09 AD agent: Auth (logon attempt:0): authenticate with 'testuser' failed Common

    2014-01-16 18:16:09 AD agent: LEAVE Function executeInstance Common

    2014-01-16 18:16:09 Executed agent '/Common/InternalPortal-Test_act_active_directory_ag', return value 0 Common

    2014-01-16 18:16:09 Following rule 'fallback' from item 'AD Auth' to ending 'Deny' Common

    2014-01-16 18:16:09 Access policy result: Logon_Deny

    So the 'testuser' is coming across in the iRules....

    Any further ideas/suggestions would be very much appreciated.

  • OK have got a bit further....

    Firstly realised I could not get the password variable because its secure and was falling fowl of the same issue as in this question:

    https://devcentral.f5.com/questions/cant-get-apm-secure-session-variable-value-in-irule

    So what I did was use VPE to configure an expression:

    session.logon.last.password1 = return "[mcget -secure {session.logon.last.password}]"
    

    Then changed the initial iRule to:

     This is the data that will be passing to the internal APM - define HTTP headers and values here
    set apmsessionuser [ACCESS::session data get "session.logon.last.username"] 
    set apmsessionpass [ACCESS::session data get "session.logon.last.password1"] 
    HTTP::header replace AGUSER $apmsessionuser
    HTTP::header replace AGPASS $apmsessionpass
    

    I can now see it authenticating ok on the internal APM, however all I get from clients is "Page Cannot Be Displayed" so looks like the portal access/rewrite isn't necessarily working properly!

    APM logs from the front end as follow:

    2014-01-16 19:46:04 Username 'testuser' Common 
    
    2014-01-16 19:46:13 Username 'testuser' Common 
    
    2014-01-16 19:46:13 Following rule 'fallback' from item 'Variable Assign' to ending 'Allow' Common 
    
    2014-01-16 19:46:13 Access policy result: LTM+APM_Mode 
    

    APM logs from the internal APM as follows:

    2014-01-16 19:49:48 Following rule 'fallback' from item 'Start' to item 'AD Auth' Common 
    
    2014-01-16 19:49:48 AD agent: ENTER Function executeInstance Common 
    
    2014-01-16 19:49:48 AD Agent: invalid user password ciphertext Common 
    
    2014-01-16 19:49:48 AD module: ENTER Function authenticateUser Common 
    
    2014-01-16 19:49:48 AD module: authenticate with 'testuser@DOMAIN.COM' successfully Common 
    
    2014-01-16 19:49:48 AD module: LEAVE Function authenticateUser Common 
    
    2014-01-16 19:49:48 AD agent: Auth (logon attempt:0): authenticate with 'testuser' successful Common 
    
    2014-01-16 19:49:48 AD agent: LEAVE Function executeInstance Common 
    
    2014-01-16 19:49:48 Executed agent '/Common/InternalPortal-Test_act_active_directory_auth_ag', return value 0 Common 
    
    2014-01-16 19:49:48 Following rule 'Successful' from item 'AD Auth' to item 'SSO Credential Mapping' Common 
    
    2014-01-16 19:49:48 Executed agent '/Common/InternalPortal-Test_act_sso_credential_mapping_1_ag', return value 0 Common 
    
    2014-01-16 19:49:48 Following rule 'fallback' from item 'SSO Credential Mapping' to item 'Full Resource Assign' Common 
    
    2014-01-16 19:49:48 Webtop '/Common/InternalPortal_SSOTest_webtop' assigned Common 
    
    2014-01-16 19:49:48 Executed agent '/Common/InternalPortal-Test2_act_full_resource_assign_ag', return value 0 Common 
    
    2014-01-16 19:49:48 Following rule 'fallback' from item 'Full Resource Assign' to ending 'Allow' Common 
    
    2014-01-16 19:49:48 StartURI from webtop: https://portal.domain.com Common 
    
    2014-01-16 19:49:48 Access policy result: Web_Application Common 
    
    2014-01-16 19:49:48 Executed agent '/Common/InternalPortal-Test2_end_allow_ag', return value 0 Common 
    
    2014-01-16 19:49:48 Session variable 'session.ad./Common/InternalPortal-Test2_act_active_directory_auth_ag.actualdomain' set to 'DOMAIN.COM' Common 
    
    2014-01-16 19:49:48 Session variable 'session.ad./Common/InternalPortal-Test2_act_active_directory_auth_ag.authresult' set to '1' Common 
    
    2014-01-16 19:49:48 Session variable 'session.ad./Common/InternalPortal-Test2_act_active_directory_auth_ag.errmsg' set to ' ' Common 
    
    2014-01-16 19:49:48 Session variable 'session.ad.last.actualdomain' set to 'DOMAIN.COM' Common 
    
    2014-01-16 19:49:48 Session variable 'session.ad.last.authresult' set to '1' Common 
    
    2014-01-16 19:49:48 Session variable 'session.ad.last.errmsg' set to ' ' Common 
    
    2014-01-16 19:49:48 Session variable 'session.assigned.resources.pa' set to '/Common/InternalPortal_SSOTest_pa_res' Common 
    
    2014-01-16 19:49:48 Session variable 'session.assigned.uuid' set to 'tmm.uuid./Common/InternalPortal-Test2.' Common 
    
    2014-01-16 19:49:48 Session variable 'session.assigned.webtop' set to '/Common/InternalPortal_SSOTest_webtop' Common 
    
    2014-01-16 19:49:48 Session variable 'session.logon.page.errorcode' set to '0' Common 
    
    2014-01-16 19:49:48 Session variable 'session.policy.result' set to 'allow' Common 
    
    2014-01-16 19:49:48 Session variable 'session.policy.result.start_uri' set to '/f5-w-68747410723a2f2f706f7274616c2e545972766576652e707269$$/' Common 
    
    2014-01-16 19:49:48 Session variable 'session.policy.result.webtop.type' set to 'web_application' Common 
    
    2014-01-16 19:49:48 Session variable 'session.sso.token.last.password' set to '**********' Common 
    
    2014-01-16 19:49:48 Session variable 'session.sso.token.last.username' set to 'testuser' Common 
    
    2014-01-16 19:49:48 Session variable 'session.webtop.customization.group' set to '/Common/InternalPortal_SSOTest_webtop_customization' 
    

    At a loss now.....

    • JoshBecigneul's avatar
      JoshBecigneul
      Icon for MVP rankMVP
      You should have an option in the portal access object to turn on logging. It may help.
  • Just to update anyone interested we engaged F5 consultancy who developed an iRule for the outer APM which deals with the session cookie name and effectively passes all traffic to the back-end APM once a user authenticates at the frontend.

     

    Obviously as it been developed by F5 consultancy I dont think its appropriate to share here but thought I'd post that it can be done!