Forum Discussion

Madiw_114772's avatar
Madiw_114772
Icon for Nimbostratus rankNimbostratus
May 02, 2014

APM Open a second startup browser after the webtop portal launch

Hello, I'm using a Portal access Webtop to redirect users to the corporate startup page after the access Policy is completed. the issue I'm having with this method is that the APM standard webtop startup page does not open while users need to access manually some webtop like application tunnel or some other specific applications not accessible through the corporate page. how can I have both pages opened the same time after the access policy is completed, the corporate startup page should be rewritten by the APM also the corporate statup page is published in APM webtop page so if there's a method to automatically click that webtop, that would fix my issue.

 

thank you for your help

 

13 Replies

  • Okay, I'm going to file this one under oddball configs, but I think I have something that will work. Tested on 11.5 so your mileage may vary.

    The basic config is a layered set of VIPs: external LTM HTTPS VIP with SSL offload, generic STREAM profile, and an iRule, and internal APM HTTP VIP with webtop and portal configuration. You can still set the secure flag in the access policy because the external interface is HTTPS.

    client -> LTM VIP -> APM VIP
    

    And now the iRule (applied at the external LTM VIP):

    when HTTP_REQUEST {
        STREAM::disable
        if { [HTTP::uri] starts_with "/vdesk/webtop.eui?webtop=" } {
            if { [ACCESS::session data get -sid [HTTP::cookie value MRHSession] session.custom.trigger] ne 1 } {
                set catch 1
                ACCESS::session data set -sid [HTTP::cookie value MRHSession] session.custom.trigger 1
            }
        }
        virtual simple-vs
    }
    when HTTP_RESPONSE {
        if { [info exists catch] } {
            unset catch
            STREAM::expression {@@ @}
            STREAM::enable
        }
    }
    

    The idea is this:

    1. If the URI starts with "/vdesk/webtop.eui?webtop=", a standard webtop invocation, check the value of a custom session variable. If it's already set, do nothing. If it isn't set, create a temporary "catch" variable. The session variable prevents the second tab from opening multiple times.

    2. Use the virtual command in the HTTP_REQUEST to send the traffic to the internal APM VIP.

    3. In the HTTP_RESPONSE event, if the catch variable exists, unset it and then use the STREAM profile to add a little piece of JavaScript to the end of the webtop document. In this case it's the "F5_Invoke_open" function that's normally used to launch links within the webtop. The only thing you need to change here is the URL that it's going to open. You can use the real value or the obfuscated URL. Either appear to work. Also, because you'll be using JavaScript to open a window without user intervention, most browsers will see that as a popup and warn you, so you'd need to set this as a trusted site to prevent that warning message.

    And of course you may still need to alter to fit your exact use case.

  • Kevin, Thanks a lot for your reply I tried a different approach this week-end and it's working fine : I'm injecting a javascript that open a second browser with the rewritten link of my resource but I have currently an issue with the sso for the resource. It seems that the sso mapping that I defined in the access policy doesn't apply to the application when I call it with the javascript, it does work when I click the webtop.

     

    Any hint about that ? also, any suggestion to improve the irule is welcomed. I'll give a try to your solution later.

     

    when CLIENT_ACCEPTED { ACCESS::restrict_irule_events disable } when RULE_INIT { set web_code " type='text/javascript'> type='text/javascript'> window.open('https://portal.corporate.com/f5-w-687474703a2f2f676f6f676c652e636f6d$$/')

     

    " }

     

    when HTTP_REQUEST { set activate_js 0 if { [HTTP::uri] ends_with "/vdesk/webtop.eui?webtop=/Cert/My_Test_webtop&webtop_type=webtop_full" } { log local0. "URI match full webtop" Don't allow data to be chunked if { [HTTP::version] eq "1.1" } { if { [HTTP::header is_keepalive] } { HTTP::header replace "Connection" "Keep-Alive" } HTTP::version "1.0" } set activate_js 1

     

    } } when HTTP_RESPONSE { if {$activate_js equals "1"} { if { [HTTP::header Content-Type] starts_with "text/html" } { if { [HTTP::header exists "Content-Length"] } { log local0. "content length: [HTTP::header {Content-Length}]" set content_length [HTTP::header "Content-Length"] } else { set content_length 1000000000 } log local0. "Collecting $content_length bytes" if { $content_length > 0 } { HTTP::collect $content_length } } } } when HTTP_RESPONSE_DATA { set web_code " type='text/javascript'> type='text/javascript'> window.open('https://portal.corporate.com/f5-w-687474703a2f2f676f6f676c652e636f6d$$/')

     

    " my trigger is 8888, it could be anything if { [HTTP::payload] contains "8888" }{ log local0. "Payload didn't contain $::exist_search!" set idx [string last "" [HTTP::payload]] if { -1 == $idx } { set idx [string last "" [HTTP::payload]] } log local0. "html end tag found at $idx" if { -1 == $idx } { set offset [HTTP::payload length] } else { set offset $idx } HTTP::payload replace $offset 0 $web_code log local0. "HTTP_REQUEST_DATA good" } }

     

  • Code 
    when CLIENT_ACCEPTED {
    ACCESS::restrict_irule_events disable
        }
        when RULE_INIT { 
           set web_code "
             
              
    
       "

    }

     

      when HTTP_REQUEST {
    set activate_js 0 
    if { [HTTP::uri] ends_with "/vdesk/webtop.eui?webtop=/Cert/My_Test_webtop&webtop_type=webtop_full" } {
    log local0. "URI match full webtop"
     Don't allow data to be chunked 
        if { [HTTP::version] eq "1.1" } { 
            if { [HTTP::header is_keepalive] } { 
               HTTP::header replace "Connection" "Keep-Alive" 
            } 
            HTTP::version "1.0" 
        } 
        set activate_js 1  
       }
    }
    when HTTP_RESPONSE { 
     if {$activate_js equals "1"} { 
        if { [HTTP::header Content-Type] starts_with "text/html" } { 
           if { [HTTP::header exists "Content-Length"] } { 
              log local0. "content length: [HTTP::header {Content-Length}]" 
              set content_length [HTTP::header "Content-Length"] 
           } else { 
           set content_length 1000000000 
         } 
         log local0. "Collecting $content_length bytes" 
         if { $content_length > 0 } { 
            HTTP::collect $content_length 
         } 
       } 
        } 
     } 
     when HTTP_RESPONSE_DATA {
        set web_code "
          
          
    
    "
    my trigger is 8888, it could be anything
    if { [HTTP::payload] contains "8888" }{
     log local0. "Payload didn't contain $::exist_search!"
    set idx [string last "" [HTTP::payload]]
    if { -1 == $idx } {
      set idx [string last "" [HTTP::payload]]
    }
    log local0. "html end tag found at $idx"
    if { -1 == $idx } {
      set offset [HTTP::payload length]
    } else {
      set offset $idx
    }
     HTTP::payload replace $offset 0 $web_code
     log local0. "HTTP_REQUEST_DATA good"
     }
    }
  • In a round-about way, we doing about the same thing. Interesting that yours works in a single VIP while the STREAM requires a layered VIP. I would contend that the STREAM is probably faster here, and wouldn't require any of the payload buffering, and HTTP 1.1 and chunking management. In any case, if you have a chance to try my version, please do and test SSO. I'll dig in if it doesn't work.

     

  • Kevin,

    Your solution is working great...In fact sso is working for both irules, I found that the sso config was broken for this specific application.

    I would like to use your solution but I need to add one more criteria to identify the user that are connecting and bring up the window depending on who's connecting.

    In my irule, I'm looking the payload and I the webtop name that is assigned only to the profile that should see the second windows

    if { [HTTP::payload] contains "8888" }
    do you have an hint on how I can do it on your irule without leveraging HTTP::payload.

    thanks

  • A few questions:

     

    1. Is "8888" actually in the HTTP payload, or in a response header? If the former, then you really don't have much choice but to use HTTP::payload.

       

    2. Could you store the information (user and webtop assignment) in session variables and check those in the request or response? Instead of looking at response payload?

       

    1. the 8888 is in the payload
    2. Sure, I could do that, I have a ldap attribute that I'm looking in the access policy and that attribute allows me to assign resources. I identified the session variable for that attribute «session.ldap.last.attr.nsrole», so I can call it in the response and use it as a trigger for the stream invoking. do you have a quick example for using APM variables in irule ...otherwise, I'll find out.

    thank you

     

  • I tested the iRule and the second browser is still opening even if the account doesn't have the good nsrole value. For testing, I modified the Irule as follow

    when HTTP_REQUEST {
        STREAM::disable
        if { [HTTP::uri] starts_with "/vdesk/webtop.eui?webtop=" } {
            if { [ACCESS::session data get -sid [HTTP::cookie value MRHSession] session.custom.trigger] ne 1 } {
               set nsrole1 "[ACCESS::session data get session.ldap.last.attr.nsrole]"
                    log local0. "nsrole1 = $nsrole1"
                    if { [ACCESS::session data get -sid [HTTP::cookie value MRHSession] session.ldap.last.attr.nsrole] contains "f5_full" } {
                    set catch 1
                    ACCESS::session data set -sid [HTTP::cookie value MRHSession] session.custom.trigger 1
                }
            }
        }
        virtual /Cert/MY_test_VS
    }
    when HTTP_RESPONSE {
        set nsrole "[ACCESS::session data get session.ldap.last.attr.nsrole]"
        log local0. "nsrole = $nsrole"
        if { [info exists catch] } {
            unset catch
            STREAM::expression {@@ @}
            STREAM::enable
        }
    }
    

    and logs show nsrole and nsrole1 entries with the trigger not in the attribute but the second browser still open

    May  8 14:28:41 fb001 info tmm7[5710]: Rule /Cert/JS_injection_layered_VIP_CERT : nsrole = | cn=cdms_abc_general_consumer,o=abc | cn=cdms_cc_consumer,o=abc | cn=containerdefaulttemplaterole,o=abc | cn=containerdefaulttemplaterole,o=abc.com,o=abc | cn=dn-affiliation management,o=abc | =abc | cn=dn-abcll centres,o=abc | cn=dn-ccma,o=abc | cn=dn-managersunion,o=abc | cn=dn-users,o=abc | cn=elearning,o=abc.com,o=abc | cn=f5_abcllcentre,o=abc | 
    
    May  8 14:28:41 fb001 info tmm2[5710]: Rule /Cert/JS_injection_layered_VIP_CERT : nsrole1 = | cn=cdms_abc_general_consumer,o=abc | cn=cdms_cc_consumer,o=abc | cn=containerdefaulttemplaterole,o=abc | cn=containerdefaulttemplaterole,o=abc.com,o=abc | cn=dn-affiliation management,o=abc | ,o=abc | cn=dn-abcll centres,o=abc | cn=dn-ccma,o=abc | cn=dn-managersunion,o=abc | cn=dn-users,o=abc | cn=elearning,o=abc.com,o=abc | cn=f5_abcllcentre,o=abc |  
    

    I'm looking how catch is set to 1 if the condition below is not matched

    if { [ACCESS::session data get -sid [HTTP::cookie value MRHSession] session.ldap.last.attr.nsrole] contains "f5_full" }

  • Just an update for future readers, The irule above is correct and everything is working fine.

    The issue was that I missed that my first irule was still applied to the APM VS so, when I removed it, this irule above worked fine.

    method 1 : irule using HTTP::payload applied to APM VS
    client -> APM VIP
    
    
    method 2 : irule with layered VIPs applied to LTM VS
    client -> LTM VIP -> APM VIP
    
  • Kevin,

    One more thing I found that this scenario (client » LTM VIP » APM VIP) is breaking the application tunnel services that are already configured. I'm getting an error message «failed to download configuration» and in the client logs, I see

    2014-05-16,12:35:25:726, 9348,13952,HOST, 0,,,, starting local TunnelServer
    2014-05-16,12:36:06:917, 9348,13952,HOST, 1, \HostCtrl.cpp, 1691, CHostCtrl::OnTimer(), TUNNEL_SERVER_READY_CHECK - configuration read timed out
    2014-05-16,12:36:06:917, 9348,13952,HOST, 1, \HostCtrl.h, 1447, CHostCtrl::Failed, Téléchargement de configuration impossible (error: 0)
    2014-05-16,12:36:06:918, 9348,13952,HOST, 1, \HostCtrl.h, 1478, CHostCtrl::Failed, Firing   event (message: download configuration impossible)
    2014-05-16,12:39:57:293, 9348,13952,SUPERHOST, 2, \BrowserContainer.cpp, 281, CBrowserContainer::CleanupHTMLDocument, Failed to get IHTMLDocument2 pointer, error 0x1
    2014-05-16,12:40:50:740, 14528,18368,PLUGINHOST, 0,,,, Request to install/update SuperHost Class
    2014-05-16,12:40:51:017, 14528,18860,PLUGINHOST, 2, \urSmartUpdateEx.cpp, 520, USmartUpdateEx::RunObjectProc(), need not install/update control, 
    

    Any hints ? thanks

    • n0vac_65442's avatar
      n0vac_65442
      Icon for Nimbostratus rankNimbostratus
      Layered VIP approach also prevents Citrix and RDP resources from launching. Is there any alternative way to inject some html code to APM response?