Table of Contents
On one of my recent deployments, I needed to set up external access using NetScaler to an internally hosted web application (Grafana).
Grafana is a cross-platform open source application for graphical representation of data from various data sources such as InfluxDB, MySQL, PostgreeSQL, Prometheus and Graphite.
The challenge here was that the customer wanted to pre-install authentication on the NetScaler, but the users were only known to the web application itself.
The question that therefore came to me was:
How can I check the user of the web application if only the web application itself has access to the user data?
I had only used standards like LDAP, RADIUS, CERT, SAML etc. for user authentication on NetScaler, but these were not useful here because the target system should not be changed.
A little research followed, and true to the motto “Read the f*** manual,” I found what I was looking for in this.
Web Authentication
“Authentication, authorization, and auditing is now able to authenticate a user to a web server, providing the credentials that the web server requires in an HTTP request and analyzing the web server response to determine that user authentication was successful.”
Web authentication | Authentication, authorization, and auditing application traffic (citrix.com)
That sounded positive to me at first. Now, as a non-web programmer, I just had to figure out how http works and what I need to do on NetScaler. So far I had only implemented rudimentary rewrite or responder policies to redirect to a specific URL path or a completely different URL or an http to https redirect.
Requirements
The following information is required to create a web authentication action:
- Name
- For the web authentication action
- IP address
- The web server to be used for authentication
- Port
- On which the web server accepts connections
- Protocol
- For access to the web server
- HTTP Request Expression
- HTTP request (expression) to be sent to the web server
- Expression to validate the Authentication
- Expression to check if the authentication was successful
Web Authentication Procedure
- The user calls the FQDN (e.g. grafana.deyda.net) of the web server
- The user is redirected to the AAA vServer to authenticate
- The user enters their credentials at the AAA vServer
- The credentials are sent to the web server by the NetScaler using the Web Authentication Action, where they are verified
- The session cookie created by the web server is sent to the NetScaler
- The session cookie is sent by the NetScaler to the user, who is redirected to the web page
Fiddler
To analyze the http requests and responses I found and used the tool Fiddler Classic (LINK). Fiddler can be used as a proxy for any browser and can also decrypt HTTPS traffic if configured accordingly.
Establishment
In order to be able to look into the HTTPS traffic with Fiddler, it must act as a man-in-the-middle proxy to intercept and decrypt the HTTPS traffic. For this, the corresponding setting (Decrypt HTTPS traffic) must be activated and the Fiddler root certificate must be installed.
- To do this, call Fiddler and open the options under Tools > Options
- Switch to the HTTPS tab, check the Decrypt HTTPS traffic checkbox and confirm the installation of the Fiddler Classic Root certificate
- In order not to let Fiddler decrypt everything, I have restricted the dropdown to …from browsers only after importing the certificate.
Creating a recording (trace)
In the status bar on the left you can see that Fiddler is active by the Capturing indicator. Next to it at All Processes you can limit the recording to Web Browsers.
- To do this, click All Processes in the status bar and then select Web Browsers
Since Fiddler was already active the whole time, I emptied the recording again before actually calling the web application (Grafana).
- To do this, click the X in the upper action area and then select Remove all
After that I called Grafana in the browser and logged in and after successful login also logged out directly.
Don’t forget to stop the recording (pause Fiddler). The easiest way to do this is to click on Capturing in the status bar.
Analysis of the recording (trace)
Because Fiddler has decrypted the HTTPS traffic, the details and not only the calls are now visible. The highlighted entry shows the POST request that was sent from the browser to Grafana when logging in.
In the Inspectors tab you can see the raw content of the request that was sent from the browser to Grafana.
So the login data is sent in JSON format via POST request to the URL https://grafana.deyda.net/grafana/login.
Thanks to decrypted HTTPS traffic, the content is visible in plain text.
So far so good, all information for the HTTP Request Expression of the Web Authentication Action was found.
The whole thing now generalized a bit with variables and broken down to the most necessary then looks for the NetScaler (HTTP Request Expression) as follows:
1 2 3 4 5 6 7 8 9 10 11 |
"POST https://" + HTTP.REQ.HOSTNAME + "/grafana/login HTTP/1.1 Host: " + HTTP.REQ.HOSTNAME + " Connection: keep-alive Content-Length: " + HTTP.REQ.CONTENT_LENGTH + " Accept: application/json User-Agent: Citrix ADC/13.1 Content-Type: application/json Origin: https://" + HTTP.REQ.HOSTNAME + " Referer: https://" + HTTP.REQ.HOSTNAME + "/grafana/login {\"user\":\"" + AAA.LOGIN.USERNAME + "\",\"password\":\"" + AAA.LOGIN.PASSWORD + "\"}" |
Continue with the info for the Expression to validate the Authentication.
For this we need to look for and look at Grafana’s answer in the Fiddler recording.
Also the http response from Grafana comes in JSON format and presents the text Logged in. In addition, two cookies (grafana_session and redirect_to) are set.
Since only an Expression to validate the Authentication has to be built in the Web Authentication Action, I didn’t care what the http response said if the user didn’t have access.
The expression I built based on the http response looks like this:
1 |
HTTP.RES.STATUS.EQ(200) && HTTP.RES.BODY(100).SET_TEXT_MODE(IGNORECASE).CONTAINS("Logged in") |
I guess with a little more knowledge about HTTP communication I would have known from the beginning that the cookie Grafana sends along with the Logged in message is probably not created for fun by Grafana. Since I ignored the cookie at the beginning, it took me some troubleshooting until I arrived at the following expression which has to be configured additionally in the Web Authentication Action under Attribute 1 to be able to use the value of the cookie from the response of Grafana:
1 |
HTTP.RES.SET_COOKIE.COOKIE("grafana_session").VALUE(0) |
The usage is then simply done by AAA.USER.ATTRIBUTE(1). In my case in a rewrite action that sets the cookie.
NetScaler
The following configures the NetScaler so that the user must log in to the AAA vServer to access the web application (Grafana)
Authentication Web Server
Using the expressions found by Fiddler, we can create the required Authentication Web Server.
- Navigate to Security > AAA – Application Traffic > Policies > Authentication > Advanced Policies > Actions > WEBAUTH
- Click Add there and enter the following:
- Name
- Name for the Authentication Web Server, e.g. webAuthAction_grafana
- Web Server IP Address
- IP address of the future content switch, e.g. 10.2.0.150
- Port
- Port on which the content switch can be reached, e.g. 443
- Protocol
- HTTPS
- HTTP Request Expression
- HTTP request sent to the web server
- Name
1 2 3 4 5 6 7 8 9 10 11 |
"POST https://" + HTTP.REQ.HOSTNAME + "/grafana/login HTTP/1.1 Host: " + HTTP.REQ.HOSTNAME + " Connection: keep-alive Content-Length: " + HTTP.REQ.CONTENT_LENGTH + " Accept: application/json User-Agent: Citrix ADC/13.1 Content-Type: application/json Origin: https://" + HTTP.REQ.HOSTNAME + " Referer: https://" + HTTP.REQ.HOSTNAME + "/grafana/login {\"user\":\"" + AAA.LOGIN.USERNAME + "\",\"password\":\"" + AAA.LOGIN.PASSWORD + "\"}" |
- Expression to validate the Authentication (Expression that checks if the authentication was successful)
1 |
HTTP.RES.STATUS.EQ(200) && HTTP.RES.BODY(100).SET_TEXT_MODE(IGNORECASE).CONTAINS("Logged in") |
- Then click > More and enter the following under Attributes 1:
1 |
HTTP.RES.SET_COOKIE.COOKIE("grafana_session").VALUE(0) |
- Confirm everything with Create
- Navigate now to Security > AAA – Application Traffic > Policies > Authentication > Advanced Policies > Policy
- Click there on Add and enter the following:
- Name
- Name of the Policy, e.g. webAuthPol_grafana
- Action Type
- WEBAUTH
- Action
- webAuthAction_grafana
- Expression
- true
- Name
- Confirm with Create
SSL certificates
- To do this, open the Admin web interface of the NetScaler and navigate to Traffic Management > SSL > Certificates > Server Certificates
- Click Install there to import the required certificate
- Enter the following and confirm the input with Install:
- Certificate-Key Pair Name
- Unique name for the certificate, e.g. wildcard.deyda.net
- Certificate File Name
- Select certificate file, e.g. deyda.net_ssl_certificate.cer
- Key File Name
- Select private key, e.g. deyda.net_private_key.key
- Certificate-Key Pair Name
- Repeat the process for the associated intermediate certificates of the certification path under Traffic Management > SSL > Certificates > CA Certificates
- Then select the installed server certificate again and click Select Action and then Link to link the certificate to the appropriate intermediate certificate
Load Balancing
Next, two load balancing virtual servers are created. One for user access and one for NetScaler access. This will later ensure that the NetScaler itself can access the Grafana server without authentication, but users cannot.
- Navigate to Traffic Management > Load Balancing > Servers
- Click Add there and enter the following:
- Name
- Name for the server object, e.g. grafana.deyda.net
- IP Address
- IP address of the Grafana server, e.g. 10.2.0.100
- Name
- Switch under Traffic Management > Load Balancing to the Services
- Click there on Add and enter or select the following accordingly:
- Service Name
- Name for the service, e.g. svc_grafana
- Existing Server -> Server
- grafana.deyda.net
- Protocol
- SSL
- Port
- Port on which the server can be reached, e.g. 443
- Service Name
- Switch under Traffic Management > Load Balancing to the Virtual Servers
- Click there on Add and enter the following to start the Load Balancing Virtual Server create for user access:
- Name
- Name of the vServer, e.g. lbvs_grafana
- Protocol
- SSL
- IP Address Type
- Non Addressable
- Name
- In the following wizard click on No Load Balancing Virtual Server Service Binding and then on Click to select
- Select the grafana service (svc_grafana) click on Select and then on Bind
- When the service is bound(1 Load Balancing Virtual Server Service Binding) click Continue
- Click on No Server Certificate and then on Click to select
- Select the server certificate and click on Select and then on Bind
- When the certificate is bound (1 Server Certificate) click Continue
- Click at the very bottom left on Done to return to the overview of the Load Balancing Virtual Server
- Click Add again on the Load Balancing Virtual Servers overview to create a second Load Balancing Virtual Server for use in the Web authentication policy. This second vServer is also created without its own IP address, since it is accessed via a content switch.
- Name
- Name of the vServer, e.g. lbvs_grafana_noauth
- Protocol
- SSL
- IP Address Type
- Non Addressable
- Name
- In the following wizard click on No Load Balancing Virtual Server Service Binding and then on Click to select
- Select the grafana service (svc_grafana) click on Select and then on Bind
- When the service is bound (1 Load Balancing Virtual Server Service Binding) click Continue
- Click on No Server Certificate and then on Click to select
- Select the server certificate and click on Select and then on Bind
- When the certificate is bound (1 Server Certificate) click Continue
- Click at the very bottom left on Done
Authentication Virtual Server (AAA)
Even if authentication is performed by the Grafana server itself, an AAA vServer must be used in order to use the web authentication policy on the load balancer.
- Navigate to Security > AAA – Application Traffic > Virtual Servers
- Under Authentication Virtual Servers, click on Add to create a new vServer
- Here enter the following:
- Name
- Name of the vServer, e.g. AAA_grafana
- IP Address Type
- Non Addressable
- Name
- Click OK
- Click on No Server Certificate and then on Click to select
- Select the server certificate and click on Select and then on Bind
- If the certificate is bound (1 Server Certificate) click Continue
- Click under Advanced Authentication Policies on No Authentication Policy
- Press Click to select
- Select the Authentication Policy and click on Select
- The Binding Details are set as follows and then confirmed using Bind
- Priority
- 100
- Goto Expression
- END
- Select Next Factor
- Click to select
- Priority
- If the Policy is bound (1 Authentication Policy) click Continue
- Click under Form Based Virtual Servers on No Load Balancing Virtual Server
- Enter the following:
- Authentication FQDN
- FQDN of the Authentication vServer, e.g. grafana.deyda.net
- Authentication FQDN
- And then click Click to select
- Select the load balancing virtual server to be secured with AAA and click on Select
- Click Bind
- Click at the bottom left on Done
Content Switching Virtual Server
The Content Switching Virtual Server receives all requests for our web application (Grafana) and distributes them to the Authentication Virtual Server and the two Load Balancing Virtual Servers according to the Content Switching Policies.
- Navigate to Traffic Management > Content Switching > Actions
- Click on Add and enter the following:
- Name
- Name of the action, e.g. cswAct_AAA_grafana
- Choose Virtual Server or Expression
- Authentication Virtual Server
- Name
- Press Click to select
- Select the Authentication Virtual Server and click Select
- Click Create
- Click on Add again and enter the following:
- Name
- Name of the action, e.g. cswAct_lbvs_grafana
- Choose Virtual Server or Expression
- Loadbalancing Virtual Server
- Name
- Press Click to select
- Select the load balancing virtual server to be secured with AAA and click on Select
- Click Create
- Click on Add again and enter the following:
- Name
- Name of the action, e.g. cswAct_lbvs_grafana_noauth
- Choose Virtual Server or Expression
- Loadbalancing Virtual Server
- Name
- Press Click to select
- Select the load balancing virtual server to be secured with AAA and click on Select
- Click Create
- Switch under Traffic Management > Content Switching to Policies
- Click Add and enter the following:
- Name
- Name of the policy, e.g. cswPol_AAA_grafana
- Action
- cswAct_AAA_grafana
- Expression:
- Name
1 |
HTTP.REQ.URL.EQ("/").NOT && (is_vpn_url || HTTP.REQ.URL.STARTSWITH("/nf/auth/")) |
- Click Create
- Click again on Add and enter the following:
- Name
- Name of the policy, e.g. cswPol_lbvs_grafana
- Action
- cswAct_lbvs_grafana
- Expression:
- Name
1 |
HTTP.REQ.HOSTNAME.SET_TEXT_MODE(IGNORECASE).EQ("grafana.deyda.net") && CLIENT.IP.SRC.EQ(10.2.0.201).NOT |
- If the Content Switch is used exclusively for Grafana, the expression can simply be set to TRUE
- The IP address is the subnet IP of the NetScaler
- Click Create
- Click Add a third time and type the following:
- Name
- Name of the policy, e.g. cswPol_lbvs_grafana_noauth
- Action
- cswAct_lbvs_grafana_noauth
- Expression:
- Name
1 |
CLIENT.IP.SRC.EQ(10.2.0.201) |
- The IP address is the NetScaler subnet IP address
- Click Create
- Navigate to Traffic Management > Content Switching > Virtual Servers
- Click Add and enter the following:
- Name
- Name of the vServer, e.g. csvs_grafana.deyda.net
- Protocol
- SSL
- IP Address Type
- IP Address
- IP Address
- IP address of the vServer, e.g. 10.2.0.150
- This IP address must match the one in the web authentication action!
- IP address of the vServer, e.g. 10.2.0.150
- Port
- Port on which the content switch can be reached, e.g. 443
- Name
- Click OK
- Under Content Switching Policy Binding, click on No Content Switching Policy Bound
- Press Click to select
- Select the Content Switching Policy cswPol_lbvs_grafana_noauth and click Select
- Enter the following:
- Priority
- 10
- Priority
- Click Bind
- When the policy is bound (1 Content Switching Policy) click on 1 Content Switching Policy
- Click on Add Binding
- Press Click to select
- Select the second content switching policy cswPol_AAA_grafana and click Select
- Enter the following:
- Priority
- 20
- Priority
- Click Bind
- Click Add Binding again and click Click to select
- Select the third content switching policy cswPol_lbvs_grafana and click Select
- Enter the following:
- Priority
- 100
- Priority
- Click on Bind and then on Close
- If the policy is bound (3 Content Switching Policies) click OK
- Now select Certificate from the Advanced Settings menu on the right side of the screen
- In the Certificate section added by this, click No Server Certificate and then Click to select to bind a server certificate
- Select the server certificate and click on Select and then on Bind
- When the certificate is bound (1 Server Certificate) click Continue and then Done
Responder
Finally, we use a responder to redirect the user’s request from the login page of the web application (Grafana) to the main page. This is necessary because the NetScaler takes over the authentication and the user would otherwise get stuck in a login loop.
- Navigate to AppExpert > Responder > Actions and click Add
- Here enter the following:
- Name
- Name of the action, e.g. respAct_grafana_subdir
- Type
- Redirect
- Expression:
- Name
1 |
"/grafana" |
- Response Status Code
- Status code that is transmitted to the browser, e.g. 302
- Click on Create and then switch to AppExpert > Responder > Policies and click there also on Add
- Enter the following:
- Name
- Name of the policy, e.g. respPol_grafana_subdir
- Action
- respAct_grafana_subdir
- Expression:
- Name
1 |
HTTP.REQ.URL.PATH.EQ("/grafana/login") |
- Click on Create
Rewrite
To make the cookie, which is generated by the NetScaler at the login to the web application, available to the user, we use a rewrite of the response that is sent to the user.
- Navigates to the section AppExpert > Rewrite > Actions and click on Add
- Type the following:
- Name
- Name of the action, e.g. rwAct_grafana_add_cookie
- Type
- INSERT_HTTP_HEADER
- Header Name
- Name of the header to insert, e.g. Set-Cookie
- Expression:
- Name
1 |
"grafana_session=" + AAA.USER.ATTRIBUTE(1) + "; path=/grafana; Max-Age=2595600; HttpOnly; SameSite=Lax" |
- Click on Create
And as a last gimmick we use another rewrite of the response for removing the NetScaler cookie to get a clean logout of the web application. This logs the user out not only from the web application itself, but also from the AAA vServer on the NetScaler.
- Click Add again to create another rewrite action
- Enter now the following:
- Name
- Name of the action, e.g. rwAct_grafana_remove_AAA_cookie
- Type
- INSERT_HTTP_HEADER
- Header Name
- Name of the header to insert, e.g. Set-Cookie
- Expression:
- Name
1 |
"NSC_TMAS=; path=/; Max-Age=-1" |
- Click Create
- Go to the section AppExpert > Rewrite > Policies
- Click on Add and enter the following:
- Name
- Name of the policy, e.g. rwPol_grafana_add_cookie
- Action
- rwAct_grafana_add_cookie
- Expression:
- Name
1 |
HTTP.REQ.COOKIE.CONTAINS("grafana_session").NOT |
- Click Create
- Then click Add again to create another rewrite policy
- Now type the following:
- Name
- Policy name, e.g. rwPol_grafana_remove_AAA_cookie
- Action
- rwAct_grafana_remove_AAA_cookie
- Expression:
- Name
1 |
HTTP.REQ.URL.TO_LOWER.STARTSWITH("/grafana/logout") && HTTP.REQ.COOKIE.CONTAINS("grafana_session") |
- Click Create
Adjustment of the Load Balancing Virtual Servers
Finally, the responder and rewrite policies must be bound to the load balancing virtual server.
- Navigate to Traffic Management > Load Balancing > Virtual Servers
- Click on the Load Balancing Virtual Server lbvs_grafana to edit it
- Click Policies in the menu (Advanced Settings) on the right side
- Then click in the Policies section on To add, please click on the + icon
- Then select the following:
- Choose Policy
- Responder
- Choose Type
- Request
- Choose Policy
- Click Continue and then click Click to select
- Select the responder policy and click Select
- Confirm the policy binding by clicking on Bind
- If the policy is bound (1 Responder Policy) click on the + right at Policies
- Now choose the following:
- Choose Policy
- Rewrite
- Choose Type
- Response
- Choose Policy
- Click Continue and then Click to select
- Select the policy (rwPol_grafana_add_cookie) and click on Select
- Confirm the policy binding with a click on Bind
- If the policy is bound (1 Rewrite Policy) click 1 Rewrite Policy in the Policies section
- Click Add Binding
- Then click on Click to select
- Select the policy (rwPol_grafana_remove_AAA_cookie) and click on Select
- Confirm the policy binding by clicking on Bind
- Click Close
- If the policies are bound (2 Rewrite Policies) click onDone
CLI commands
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
add ssl certKey grafana.deyda.net -cert deyda.net_ssl_certificate.cer -key deyda.net_private_key.key -inform PEM add ssl certKey deyda.net_ssl_INTERMEDIATE -cert deyda.net_ssl_INTERMEDIATE.cer -inform PEM link ssl certKey grafana.deyda.net deyda.net_ssl_INTERMEDIATE add server grafana.deyda.net 10.2.0.100 add service svc_grafana grafana.deyda.net SSL 443 add lb vserver lbvs_grafana SSL 0.0.0.0 0 bind lb vserver lbvs_grafana svc_grafana bind ssl vserver lbvs_grafana -certkeyName grafana.deyda.net add lb vserver lbvs_grafana_noauth SSL 0.0.0.0 0 bind lb vserver lbvs_grafana_noauth svc_grafana bind ssl vserver lbvs_grafana_noauth -certkeyName grafana.deyda.net add authentication webAuthAction webAuthAction_grafana -serverIP 10.2.0.150 -serverPort 443 -fullReqExpr "\"POST https://\" + HTTP.REQ.HOSTNAME + \"/grafana/login HTTP/1.1\nHost: \" + HTTP.REQ.HOSTNAME + \"\nConnection: keep-alive\nContent-Length: \" + HTTP.REQ.CONTENT_LENGTH + \"\nAccept: application/json\nUser-Agent: Citrix ADC/13.1\nContent-Type: application/json\nOrigin: https://\" + HTTP.REQ.HOSTNAME + \"\n\n{\\\"user\\\":\\\"\" + AAA.LOGIN.USERNAME + \"\\\",\\\"password\\\":\\\"\" + AAA.LOGIN.PASSWORD + \"\\\",\\\"email\\\":\\\"\\\"}\"" -scheme https -successRule "HTTP.RES.STATUS.EQ(200) && HTTP.RES.BODY(100).SET_TEXT_MODE(IGNORECASE).CONTAINS(\"Logged in\")" -Attribute1 "HTTP.RES.SET_COOKIE.COOKIE(\"grafana_session\").VALUE(0)" add authentication Policy webAuthPol_grafana -rule true -action webAuthAction_grafana add authentication vserver AAA_grafana SSL 0.0.0.0 bind ssl vserver AAA_grafana -certkeyName grafana.deyda.net bind authentication vserver AAA_grafana -policy webAuthPol_grafana -priority 100 -gotoPriorityExpression END set lb vserver lbvs_grafana -AuthenticationHost grafana.deyda.net -Authentication ON -authnVsName AAA_grafana add cs action cswAct_AAA_grafana -targetVserver AAA_grafana add cs action cswAct_lbvs_grafana -targetLBVserver lbvs_grafana add cs action cswAct_lbvs_grafana_noauth -targetLBVserver lbvs_grafana_noauth add cs policy cswPol_AAA_grafana -rule "HTTP.REQ.URL.EQ(\"/\").NOT && (is_vpn_url || HTTP.REQ.URL.STARTSWITH(\"/nf/auth/\"))" -action cswAct_AAA_grafana add cs policy cswPol_lbvs_grafana -rule "HTTP.REQ.HOSTNAME.SET_TEXT_MODE(IGNORECASE).EQ(\"grafana.deyda.net\") && CLIENT.IP.SRC.EQ(10.2.0.201).NOT" -action cswAct_lbvs_grafana add cs policy cswPol_lbvs_grafana_noauth -rule "CLIENT.IP.SRC.EQ(10.2.0.201)" -action cswAct_lbvs_grafana_noauth add cs vserver csvs_grafana.deyda.net SSL 10.2.0.150 443 bind ssl vserver csvs_grafana.deyda.net -certkeyName grafana.deyda.net bind cs vserver csvs_grafana.deyda.net -policyName cswPol_lbvs_grafana_noauth -priority 10 bind cs vserver csvs_grafana.deyda.net -policyName cswPol_AAA_grafana -priority 20 bind cs vserver csvs_grafana.deyda.net -policyName cswPol_lbvs_grafana -priority 100 add responder action respAct_grafana_subdir redirect "\"/grafana\"" -responseStatusCode 302 add responder policy respPol_grafana_subdir "HTTP.REQ.URL.PATH.EQ(\"/grafana/login\")" respAct_grafana_subdir bind lb vserver lbvs_grafana -policyName respPol_grafana_subdir -priority 100 -gotoPriorityExpression END -type REQUEST add rewrite action rwAct_grafana_add_cookie insert_http_header Set-Cookie "\"grafana_session=\" + AAA.USER.ATTRIBUTE(1) + \"; path=/grafana; Max-Age=2595600; HttpOnly; SameSite=Lax\"" add rewrite action rwAct_grafana_remove_AAA_cookie insert_http_header Set-Cookie "\"NSC_TMAS=; path=/; Max-Age=-1\"" add rewrite policy rwPol_grafana_add_cookie "HTTP.REQ.COOKIE.CONTAINS(\"grafana_session\").NOT" rwAct_grafana_add_cookie add rewrite policy rwPol_grafana_remove_AAA_cookie "HTTP.REQ.URL.TO_LOWER.STARTSWITH(\"/grafana/logout\") && HTTP.REQ.COOKIE.CONTAINS(\"grafana_session\")" rwAct_grafana_remove_AAA_cookie bind lb vserver lbvs_grafana -policyName rwPol_grafana_remove_AAA_cookie -priority 110 -gotoPriorityExpression END -type RESPONSE bind lb vserver lbvs_grafana -policyName rwPol_grafana_add_cookie -priority 100 -gotoPriorityExpression END -type RESPONSE |