Monday, November 3, 2014

Certificate Expiration Notification v8.1.02

The following article covers how to setup notifications for upcoming certificate expirations.  This solution will report which client certificates are due to expire in the next 30 days and the FIP in which they reside as well as which trusted certificates (under tasks > manage certificates) are due to expire in the same time frame.

Step 1
The below link to GitHub provides the two files you will need.  The first is a Layer 7 policy (xml file) for you to import into your gateway at the service url /parse_certs .  This service will accept the data pulled from the database by the shell script and craft the email message to be sent to the gateway administrators.

https://github.com/Benjaneer/Layer7

Step 2
Once you have the policy in your service it needs to be updated on line 43 Send Email Alert assertion.  The host, from, and to need to be set according to you environment.  Nothing else in the policy should require any changes for this solution to work.

Step 3
The shell script (also on GitHub) should be setup on your primary or backup database gateway node and can be scheduled using crontab (either one, not both).  The request is routed into the gateway via localhost port 8080.  This requires that port 8080 not be disabled, though it need not be accessible from anywhere else.  If you prefer you can route to 8443 but will have to resolve the server certificate hostname mismatch.  For other versions of the gateway the database schema may have changed and therefore the query in this script will need to be changed accordingly.  You should also ensure that the 'maximum message size' limit for the 8080 listen port advanced setting is not preventing the message from being received.  To change the port or hostname used by the shell script to send the data into the policy update the curl command url.

Step 4
Use chmod to make the shell script executable on the gateway.

Step 5
Test!

Step 6
Setup a cron job to periodically run the script and alert you of upcoming certificate expirations.  In the shell script (shown below) you can change the days parameter to adjust how far out expirations should be reported on.

mysql -X -e "select c.user_id as uid,concat('FIP:',p.name) as repository,case when u.name is null then c.login else u.name end as name,c.cert as cert from ssg.client_cert as c left join ssg.identity_provider as p on c.provider = p.goid left join ssg.fed_user as u on unhex(c.user_id) = u.goid union select hex(goid) as uid,'Trusted Certificate' as repository,name,cert_base64 as cert from ssg.trusted_cert;" > check.xml
curl -X POST -d @check.xml -H "Content-Type: application/xml; charset=utf-8" http://localhost:8080/parse_certs?days=30
rm -f check.xml

Thursday, July 3, 2014

HTTP Authentication Realm

Special thanks to the Layer 7 support team for coming through with this "undocumented feature" to resolve this exposure until it is accessible through the policy manager.

When crafting services that make use of the "Require HTTP Basic Credentials" assertion you may have noticed that the realm for the challenge that is returned when the client does not preemptively authenticate is "L7SSGBasicRealm".

You can add a WWW-Authenticate basic realm to the header of the response before enforcing the require HTTP credentials, however this results in the first authentication challenge having two authenticate headers, and while the first one appears in the prompt, both are visible when examining the traffic; furthermore if the client cancels or fails the first challenge then the following two will still present only the L7BasicRealm.

The solution is to edit the assertion in notepad to the following format:

<?xml version="1.0" encoding="UTF-8"?>
<wsp:Policy xmlns:L7p="http://www.layer7tech.com/ws/policy" xmlns:wsp="http://schemas.xmlsoap.org/ws/2002/12/policy">
    <wsp:All wsp:Usage="Required">
        <L7p:HttpBasic>
            <L7p:AssertionComment assertionComment="included">
                <L7p:Properties mapValue="included">
                    <L7p:entry>
                        <L7p:key stringValue="RIGHT.COMMENT"/>
                        <L7p:value stringValue="//realm your.domain.com"/>
                    </L7p:entry>
                </L7p:Properties>
            </L7p:AssertionComment>
            <L7p:Realm stringValue="your.domain.com"/>
        </L7p:HttpBasic>
    </wsp:All>
</wsp:Policy>

This will result in the challenge returned to the client to have only one authenticate header with the realm of "your.domain.com" (appears twice in the xml, once for the realm and once for the comment) and the same for the two following challenges.

This was tested on 8.1.02 and was not tested using a context variable.

Tuesday, June 10, 2014

Hardening the Layer 7 Gateway

Introduction

While I am sure that everyone keeps their Layer 7 Gateways fully updated with each and every patch as soon as it is released and that these patches never cause any issues with existing services and integrations and that Layer 7 Technologies thoroughly and comprehensively test the patches before they are release as soon as they themselves discover an issue because no one would want to maliciously attack someone else's system and every day is filled with sunshine and rainbows...

Meanwhile, here in the real world, part of our job is to obfuscate the fact that we are using Layer 7's product, because it is possible that there is an issue which has not been corrected, or even discovered by the white hats, and once it is known it will take time to fix, test, and deploy.  If an issue affects our Layer 7 appliance and attackers know that we are using Layer 7 then they also know how to attack us effectively.  For these reasons, to more efficiently protect ourselves and the organizations for which we work, we must configure our gateways to conceal that they are Layer 7 appliances.

Overwriting the default error response message

You may have noticed that when you call one of your services and the service fails, or if the request does not resolve to a service, then the appliance returns a message that says l7 all over it.  Hardening your policies is another conversation, but at the end of this section you should never see those messages again unless you explicitly set your policy(s) to sent them.

Global Policy Fragment

First off, create a policy (fragment, not a service) and lets name it 'Generic Error' then select policy type 'Global Policy Fragment' with policy tag 'message-received'; I also like to check the 'Intended for SOAP Services' box because fragments intended for soap services can be used for non-soap services and fragments not intended for soap do not seem to appear in the include list for non soap services, though I am not sure that it makes a difference here.

This fragment will be executed every time a message is received, even if the request does not resolve to a service.  By adding a 'Customize Error Response' in this fragment we can globally overwrite the Layer 7 default failure message.  The following is a sample error response, the only assertion that should be in this policy fragment.

Sample Customize Error Response Assertion

<?xml version="1.0" encoding="UTF-8"?>
<wsp:Policy xmlns:L7p="http://www.layer7tech.com/ws/policy" xmlns:wsp="http://schemas.xmlsoap.org/ws/2002/12/policy">
    <wsp:All wsp:Usage="Required">
        <L7p:CustomizeErrorResponse>
            <L7p:Content stringValueReference="inline"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Body>
        <soapenv:Fault>
            <faultcode>soapenv:Server</faultcode>
            <faultstring>Internal Server Error</faultstring>
            <faultactor>${request.url}</faultactor>
            <detail>Internal Server Error</detail>
        </soapenv:Fault>
    </soapenv:Body>
</soapenv:Envelope>]]></L7p:Content>
            <L7p:ContentType stringValue="text/xml; charset=UTF-8"/>
            <L7p:ExtraHeaders nameValuePairArray="included"/>
        </L7p:CustomizeErrorResponse>
    </wsp:All>
</wsp:Policy>

Catch-All (aka wildcard service)

Next off, as some of you have already been guided to do, is to create a 'catch-all' service.  By creating an API web service with a URI of * any request that does not resolve to a more specific URI will instead resolve to the wildcard.  This service can be used to capture and handle all requests that enter service resolution but would otherwise fail to resolve and in doing so end up sending the default Layer 7 failure response.  While this service is able to replace the error response in the same way as the generic error fragment there are still a couple of ways for a request to fail before reaching service resolution and therefor not run the catch-all, and if the generic error fragment is not in place, to receive the Layer 7 default failure message.

There are a few things that I would recommend to do in the catch-all, like logging information about the request, that I do not recommend to do in the generic error fragment; because the generic error fragment will run for every request and therefore should be as lean as possible.  The catch-all is only servicing requests that have already failed to resolve properly and we therefore do not mind taking a few extra milliseconds to triage the nature of the issue (i.e. does one of our customers need help or are we being probed).  Remember to check all the HTTP methods for the catch-all to make it more widely applicable.

Ping

Personally, I went quite a long time before I was aware of the ping service, now that I am aware of it I am acutely aware.  That is to say, this service betrays the fact that it is a Layer 7 appliance.  This service should not be accessible externally and because it is on by default for the default service ports you must go in and disable it for those ports, or make those ports inaccessible externally and host your services over another port.  Don't get me wrong, the service is useful, but it should be kept internal only.  I recommend to turn it on another port when turning it off for the default ports.

Under Tasks -> Manage Listen Ports, select port 9443 and click the Properties button, expand 'Built-in services' and uncheck the 'Ping service'.  You cannot change the settings on a port over which you are connected using the policy manager, you must therefore disconnect and re-connect over 9443 in order to uncheck the Ping service for port 8443.  You can turn it on for any port that is accessible to your internal network and firewalled off from the internet.

As a practical matter, the only 'Enabled Features' that you want checked on your externally accessible ports are:
  • Published service message input
  • WS-Trust security token service *if you use WS-Security
  • WSDL download service *if you host SOAP web services
  • *if you use the SecureSpan XML VPN Client then you will want to turn on some others
    • Policy download service
    • WS-Trust security token service *if you use WS-Security or SAML
    • Certificate signing service
    • Password changing service
    • WSDL download service

Authentication methods

I strongly recommend mutual-SSL over TLS as part of dual-factor authentication for the strongest security.  As the second factor I suggest some sort of token, such as WS, SAML, or OAuth depending on which best suits your use case.  At a minimum you should never use http, there is no excuse to not at least use server side SSL.  The only logical argument against it is to avoid the additional overhead, however this system (along with most others) has been optimized for https and as a result is slower when using unsecured http, therefore this argument does not hold up.

The point being, regardless of which authentication method(s) you are using, configure your server certificate and require in policy that your clients connect using SSL.  You can require SSL in the port settings, but that would reduce the traffic (troubleshooting information) available in the catch-all.

Thursday, May 29, 2014

Diagnostic Service

<?xml version="1.0" encoding="UTF-8"?>
<wsp:Policy xmlns:L7p="http://www.layer7tech.com/ws/policy" xmlns:wsp="http://schemas.xmlsoap.org/ws/2002/12/policy">
    <wsp:All wsp:Usage="Required">
        <wsp:OneOrMore wsp:Usage="Required">
            <L7p:SslAssertion/>
            <L7p:CustomizeErrorResponse>
                <L7p:AssertionComment assertionComment="included">
                    <L7p:Properties mapValue="included">
                        <L7p:entry>
                            <L7p:key stringValue="RIGHT.COMMENT"/>
                            <L7p:value stringValue="//401 - SSL required."/>
                        </L7p:entry>
                    </L7p:Properties>
                </L7p:AssertionComment>
                <L7p:Content stringValueReference="inline"><![CDATA[{
  "success": false,
  "fault": {
    "faultcode": "soapenv:Client",
    "faultstring": "SSL required",
    "faultactor": "${request.url}",
    "detail": "SSL required."
  }
}]]></L7p:Content>
                <L7p:ContentType stringValue="application/json; charset=UTF-8"/>
                <L7p:ExtraHeaders nameValuePairArray="included"/>
                <L7p:HttpStatus stringValue="401"/>
            </L7p:CustomizeErrorResponse>
            <L7p:FalseAssertion/>
        </wsp:OneOrMore>
        <wsp:All wsp:Usage="Required">
            <wsp:OneOrMore wsp:Usage="Required">
                <wsp:All wsp:Usage="Required">
                    <L7p:SslAssertion>
                        <L7p:RequireClientAuthentication booleanValue="true"/>
                    </L7p:SslAssertion>
                    <L7p:AuditDetailAssertion>
                        <L7p:Detail stringValueReference="inline"><![CDATA[subject.dn.cn:${request.ssl.clientCertificate.subject.dn.cn};
serial:${request.ssl.clientCertificate.serial};
notAfter:${request.ssl.clientCertificate.notAfter};
issuer:${request.ssl.clientCertificate.issuer};
extendedKeyUsageValues:${request.ssl.clientCertificate.extendedKeyUsageValues};
subject:${request.ssl.clientCertificate.subject};
thumbprintSHA1:${request.ssl.clientCertificate.thumbprintSHA1};]]></L7p:Detail>
                    </L7p:AuditDetailAssertion>
                </wsp:All>
                <wsp:All wsp:Usage="Required">
                    <wsp:OneOrMore wsp:Usage="Required">
                        <wsp:OneOrMore wsp:Usage="Required">
                            <L7p:ComparisonAssertion>
                                <L7p:CaseSensitive booleanValue="false"/>
                                <L7p:Expression1 stringValue="${request.ssl.clientCertificate}"/>
                                <L7p:Expression2 stringValue=""/>
                                <L7p:Operator operator="EMPTY"/>
                                <L7p:Predicates predicates="included">
                                    <L7p:item binary="included">
                                    <L7p:CaseSensitive booleanValue="false"/>
                                    <L7p:Operator operator="EMPTY"/>
                                    <L7p:RightValue stringValue=""/>
                                    </L7p:item>
                                </L7p:Predicates>
                            </L7p:ComparisonAssertion>
                            <L7p:ComparisonAssertion>
                                <L7p:CaseSensitive booleanValue="false"/>
                                <L7p:Expression1 stringValue="${request.ssl.clientCertificate}"/>
                                <L7p:Expression2 stringValue=""/>
                                <L7p:Negate booleanValue="true"/>
                                <L7p:Operator operator="EMPTY"/>
                                <L7p:Predicates predicates="included">
                                    <L7p:item binary="included">
                                    <L7p:CaseSensitive booleanValue="false"/>
                                    <L7p:Negated booleanValue="true"/>
                                    <L7p:Operator operator="EMPTY"/>
                                    <L7p:RightValue stringValue=""/>
                                    </L7p:item>
                                </L7p:Predicates>
                            </L7p:ComparisonAssertion>
                            <L7p:CustomizeErrorResponse>
                                <L7p:AssertionComment assertionComment="included">
                                    <L7p:Properties mapValue="included">
                                    <L7p:entry>
                                    <L7p:key stringValue="RIGHT.COMMENT"/>
                                    <L7p:value stringValue="//401 - No credentials were provided.  Request was not authenticated."/>
                                    </L7p:entry>
                                    </L7p:Properties>
                                </L7p:AssertionComment>
                                <L7p:Content stringValueReference="inline"><![CDATA[{
  "success": false,
  "fault": {
    "faultcode": "soapenv:Client",
    "faultstring": "Access Denied",
    "faultactor": "${request.url}",
    "detail": {
      "datetime": "${request.time}",
      "errorcode": "401",
      "message": "No credentials were provided.  Request was not authenticated."
    }
  }
}]]></L7p:Content>
                                <L7p:ContentType stringValue="application/json; charset=UTF-8"/>
                                <L7p:ExtraHeaders nameValuePairArray="included"/>
                                <L7p:HttpStatus stringValue="401"/>
                            </L7p:CustomizeErrorResponse>
                        </wsp:OneOrMore>
                        <wsp:All wsp:Usage="Required">
                            <L7p:AuditDetailAssertion>
                                <L7p:Detail stringValueReference="inline"><![CDATA[Usage: ${request.ssl.clientCertificate.extendedKeyUsageValues}
crlSign: ${request.ssl.clientCertificate.keyUsage.dataEncipherment}
dataEncipherment: ${request.ssl.clientCertificate.keyUsage.dataEncipherment}
decipherOnly: ${request.ssl.clientCertificate.keyUsage.decipherOnly}
digitalSignature: ${request.ssl.clientCertificate.keyUsage.digitalSignature}
encipherOnly: ${request.ssl.clientCertificate.keyUsage.encipherOnly}
keyAgreement: ${request.ssl.clientCertificate.keyUsage.keyAgreement}
keyCertSign: ${request.ssl.clientCertificate.keyUsage.keyCertSign}
keyEncipherment: ${request.ssl.clientCertificate.keyUsage.keyEncipherment}
nonRepudiation: ${request.ssl.clientCertificate.keyUsage.nonRepudiation}]]></L7p:Detail>
                            </L7p:AuditDetailAssertion>
                            <L7p:ComparisonAssertion>
                                <L7p:CaseSensitive booleanValue="false"/>
                                <L7p:Expression1 stringValue="${request.ssl.clientCertificate.extendedKeyUsageValues}"/>
                                <L7p:Expression2 stringValue="1.3.6.1.5.5.7.3.2"/>
                                <L7p:Negate booleanValue="true"/>
                                <L7p:Operator operator="CONTAINS"/>
                                <L7p:Predicates predicates="included">
                                    <L7p:item binary="included">
                                    <L7p:CaseSensitive booleanValue="false"/>
                                    <L7p:Negated booleanValue="true"/>
                                    <L7p:Operator operator="CONTAINS"/>
                                    <L7p:RightValue stringValue="1.3.6.1.5.5.7.3.2"/>
                                    </L7p:item>
                                </L7p:Predicates>
                            </L7p:ComparisonAssertion>
                            <L7p:CustomizeErrorResponse>
                                <L7p:AssertionComment assertionComment="included">
                                    <L7p:Properties mapValue="included">
                                    <L7p:entry>
                                    <L7p:key stringValue="RIGHT.COMMENT"/>
                                    <L7p:value stringValue="//403 - The certificate used to sign the request is not provisioned for use as a client certificate."/>
                                    </L7p:entry>
                                    </L7p:Properties>
                                </L7p:AssertionComment>
                                <L7p:Content stringValueReference="inline"><![CDATA[{
  "success": false,
  "fault": {
    "faultcode": "soapenv:Client",
    "faultstring": "Access Denied",
    "faultactor": "${request.url}",
    "detail": {
      "datetime": "${request.time}",
      "errorcode": "403",
      "message": "The certificate used to sign the request is not provisioned for use as a client certificate."
    }
  }
}]]></L7p:Content>
                                <L7p:ContentType stringValue="application/json; charset=UTF-8"/>
                                <L7p:ExtraHeaders nameValuePairArray="included"/>
                                <L7p:HttpStatus stringValue="403"/>
                            </L7p:CustomizeErrorResponse>
                        </wsp:All>
                        <L7p:CustomizeErrorResponse>
                            <L7p:AssertionComment assertionComment="included">
                                <L7p:Properties mapValue="included">
                                    <L7p:entry>
                                    <L7p:key stringValue="RIGHT.COMMENT"/>
                                    <L7p:value stringValue="//403 - The certificate used to sign the request is not acceptable."/>
                                    </L7p:entry>
                                </L7p:Properties>
                            </L7p:AssertionComment>
                            <L7p:Content stringValueReference="inline"><![CDATA[{
  "success": false,
  "fault": {
    "faultcode": "soapenv:Client",
    "faultstring": "Authentication Failed",
    "faultactor": "${request.url}",
    "detail": {
      "datetime": "${request.time}",
      "errorcode": "403",
      "message": "The certificate used to sign the request is not acceptable."
    }
  }
}]]></L7p:Content>
                            <L7p:ContentType stringValue="application/json; charset=UTF-8"/>
                            <L7p:ExtraHeaders nameValuePairArray="included"/>
                            <L7p:HttpStatus stringValue="403"/>
                        </L7p:CustomizeErrorResponse>
                        <L7p:assertionComment>
                            <L7p:Properties mapValue="included">
                                <L7p:entry>
                                    <L7p:key stringValue="RIGHT.COMMENT"/>
                                    <L7p:value stringValue="//try to log requestor properties"/>
                                </L7p:entry>
                            </L7p:Properties>
                        </L7p:assertionComment>
                    </wsp:OneOrMore>
                    <L7p:ForEachLoop L7p:Usage="Required"
                        loopVariable="audit.details" variablePrefix="this.current">
                        <wsp:OneOrMore wsp:Usage="Required">
                            <L7p:ComparisonAssertion>
                                <L7p:CaseSensitive booleanValue="false"/>
                                <L7p:Expression1 stringValue="${this.current.messageId}"/>
                                <L7p:Operator operatorNull="null"/>
                                <L7p:Predicates predicates="included">
                                    <L7p:item dataType="included">
                                    <L7p:Type variableDataType="string"/>
                                    </L7p:item>
                                    <L7p:item binary="included">
                                    <L7p:CaseSensitive booleanValue="false"/>
                                    <L7p:Negated booleanValue="true"/>
                                    <L7p:RightValue stringValue="6"/>
                                    </L7p:item>
                                    <L7p:item binary="included">
                                    <L7p:CaseSensitive booleanValue="false"/>
                                    <L7p:Negated booleanValue="true"/>
                                    <L7p:RightValue stringValue="4113"/>
                                    </L7p:item>
                                </L7p:Predicates>
                            </L7p:ComparisonAssertion>
                            <wsp:All wsp:Usage="Required">
                                <L7p:ComparisonAssertion>
                                    <L7p:CaseSensitive booleanValue="false"/>
                                    <L7p:Expression1 stringValue="${this.current.messageId}"/>
                                    <L7p:Operator operatorNull="null"/>
                                    <L7p:Predicates predicates="included">
                                    <L7p:item dataType="included">
                                    <L7p:Type variableDataType="string"/>
                                    </L7p:item>
                                    <L7p:item binary="included">
                                    <L7p:CaseSensitive booleanValue="false"/>
                                    <L7p:RightValue stringValue="6"/>
                                    </L7p:item>
                                    </L7p:Predicates>
                                </L7p:ComparisonAssertion>
                                <L7p:CustomizeErrorResponse>
                                    <L7p:AssertionComment assertionComment="included">
                                    <L7p:Properties mapValue="included">
                                    <L7p:entry>
                                    <L7p:key stringValue="RIGHT.COMMENT"/>
                                    <L7p:value stringValue="//403 - Valid client certificate required.  The client certificate used to sign the request is expired."/>
                                    </L7p:entry>
                                    </L7p:Properties>
                                    </L7p:AssertionComment>
                                    <L7p:Content stringValueReference="inline"><![CDATA[{
  "success": false,
  "fault": {
    "faultcode": "soapenv:Client",
    "faultstring": "Expired Client Certificate",
    "faultactor": "${request.url}",
    "detail": {
      "datetime": "${request.time}",
      "errorcode": "403",
      "message": "Valid client certificate required.  The client certificate used to sign the request is expired."
    }
  }
}]]></L7p:Content>
                                    <L7p:ContentType stringValue="application/json;charset=utf-8"/>
                                    <L7p:ExtraHeaders nameValuePairArray="included"/>
                                    <L7p:HttpStatus stringValue="403"/>
                                </L7p:CustomizeErrorResponse>
                            </wsp:All>
                        </wsp:OneOrMore>
                    </L7p:ForEachLoop>
                    <L7p:FalseAssertion/>
                </wsp:All>
            </wsp:OneOrMore>
        </wsp:All>
        <L7p:HardcodedResponse>
            <L7p:Base64ResponseBody stringValue="ewogICJzdWNjZXNzIjogdHJ1ZSwKICAiZGV0YWlsIjogewogICAgIkxheWVyNyI6IHsKICAgICAgInBvbGljeVJlc3VsdCI6ICJZb3VyIGNsaWVudCBjZXJ0aWZpY2F0ZSBpcyBwcm9wZXJseSBhdHRhY2hlZC4gIGFwcGxpY2F0aW9uL2pzb24iCiAgICB9LAogICAgIkNsaWVudCI6IHsKICAgICAgIlN1YmplY3RDTiI6ICIke3JlcXVlc3Quc3NsLmNsaWVudENlcnRpZmljYXRlLnN1YmplY3QuZG4uY259IiwKICAgICAgIlNlcmlhbE51bSI6ICIke3JlcXVlc3Quc3NsLmNsaWVudENlcnRpZmljYXRlLnNlcmlhbH0iLAogICAgICAiSXNzdWVyQ04iOiAiJHtyZXF1ZXN0LnNzbC5jbGllbnRDZXJ0aWZpY2F0ZS5pc3N1ZXIuZG4uY259IiwKICAgICAgIkV4cGlyYXRpb24iOiAiJHtyZXF1ZXN0LnNzbC5jbGllbnRDZXJ0aWZpY2F0ZS5ub3RBZnRlcn0iLAogICAgICAiRlFETiI6ICIke3JlcXVlc3Quc3NsLmNsaWVudENlcnRpZmljYXRlLnN1YmplY3R9IiwKICAgICAgIlN1YmplY3RLZXlJRCI6ICIke3JlcXVlc3Quc3NsLmNsaWVudENlcnRpZmljYXRlLnN1YmplY3RLZXlJZGVudGlmaWVyfSIKICAgICAgIlVzYWdlIjogIiR7cmVxdWVzdC5zc2wuY2xpZW50Q2VydGlmaWNhdGUuZXh0ZW5kZWRLZXlVc2FnZVZhbHVlc30iCiAgICB9LAogICAgIlJlcXVlc3QiOiB7CiAgICAgICJVUkwiOiAiJHtyZXF1ZXN0LnVybH0iLAogICAgICAiTWV0aG9kIjogIiR7cmVxdWVzdC5odHRwLm1ldGhvZH0iLAogICAgICAiU2l6ZSI6ICIke3JlcXVlc3Quc2l6ZX0iCiAgICB9LAogICAgIkhlYWRlciI6IHsKICAgICAgIkNvbnRlbnQtVHlwZSI6ICIke3JlcXVlc3QuaHR0cC5oZWFkZXIuY29udGVudC10eXBlfSIsCiAgICAgICJDb250ZW50LUxlbmd0aCI6ICIke3JlcXVlc3QuaHR0cC5oZWFkZXIuY29udGVudC1sZW5ndGh9IiwKICAgICAgIlNvYXBBY3Rpb24iOiAiJHtyZXF1ZXN0Lmh0dHAuaGVhZGVyLnNvYXBhY3Rpb259IgogICAgfQogIH0KfQo="/>
            <L7p:ResponseContentType stringValue="text/plain; charset=UTF-8"/>
        </L7p:HardcodedResponse>
    </wsp:All>
</wsp:Policy>

Thursday, April 24, 2014

Fragment Include Lookup Service

This service was written for version 8.0 of the Layer 7 Gateway, there was a schema change in the database from version 6.2 which will prevent it from working, and it has not been tested on version 7.x.

In order to use this service you must first setup a connection to your layer 7 database.  Then create an API and paste the below policy definition into it.  Lastly update these assertions; 10: Authenticate against internal identity provider, make sure that it is pointed to your provider as the internal object ID might not match from my environment to yours; 38: Perform JDBC Query, point it to your database connection; 63: Perform JDBC Query, point it to your database connection.  Now you can call this service, initially it will list out your fragments; then when you pass it the parameter described on the html page returned by the service it will list out the services that call the fragment you specify.

Note: It instructs you to pass the fragment name and then does a wildcard search on it, if the results are not as expected then you can use the service to search by objectid parameter from the hex column value instead of the name.

<?xml version="1.0" encoding="UTF-8"?>
<wsp:Policy xmlns:L7p="http://www.layer7tech.com/ws/policy" xmlns:wsp="http://schemas.xmlsoap.org/ws/2002/12/policy">
    <wsp:All wsp:Usage="Required">
        <wsp:OneOrMore wsp:Usage="Required">
            <L7p:SslAssertion/>
            <wsp:All wsp:Usage="Required">
                <L7p:CustomizeErrorResponse>
                    <L7p:ErrorLevel errorLevel="DROP_CONNECTION"/>
                    <L7p:ExtraHeaders nameValuePairArray="included"/>
                </L7p:CustomizeErrorResponse>
                <L7p:FalseAssertion/>
            </wsp:All>
            <L7p:assertionComment>
                <L7p:Properties mapValue="included">
                    <L7p:entry>
                        <L7p:key stringValue="RIGHT.COMMENT"/>
                        <L7p:value stringValue="// require secure communications"/>
                    </L7p:entry>
                </L7p:Properties>
            </L7p:assertionComment>
        </wsp:OneOrMore>
        <wsp:OneOrMore wsp:Usage="Required">
            <wsp:All wsp:Usage="Required">
                <L7p:HttpBasic/>
                <L7p:Authentication>
                    <L7p:IdentityProviderOid goidValue="0000000000000000fffffffffffffffe"/>
                </L7p:Authentication>
            </wsp:All>
            <wsp:All wsp:Usage="Required">
                <L7p:CustomizeErrorResponse>
                    <L7p:Content stringValueReference="inline"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Body>
        <soapenv:Fault>
            <faultcode>soapenv:Client</faultcode>
            <faultstring>Access Denied</faultstring>
            <faultactor>${request.url}</faultactor>
            <detail>
                <datetime>${request.time}</datetime>
                <errorcode>403: Forbidden</errorcode>
                <message>The credentials you have provided are not permitted to access this service.</message>
        </detail>
        </soapenv:Fault>
    </soapenv:Body>
</soapenv:Envelope>]]></L7p:Content>
                    <L7p:ContentType stringValue="text/xml;charset=utf-8"/>
                    <L7p:ExtraHeaders nameValuePairArray="included"/>
                    <L7p:HttpStatus stringValue="403"/>
                </L7p:CustomizeErrorResponse>
                <L7p:FalseAssertion/>
            </wsp:All>
            <L7p:assertionComment>
                <L7p:Properties mapValue="included">
                    <L7p:entry>
                        <L7p:key stringValue="RIGHT.COMMENT"/>
                        <L7p:value stringValue="// require http admin credentials"/>
                    </L7p:entry>
                </L7p:Properties>
            </L7p:assertionComment>
        </wsp:OneOrMore>
        <wsp:OneOrMore wsp:Usage="Required">
            <L7p:RateLimit>
                <L7p:BlackoutPeriodInSeconds stringValue="10"/>
                <L7p:CounterName stringValue="${request.tcp.localIP}-${service.policy.guid}-${request.tcp.localPort}-${request.ssl.clientCertificate.subject}-${request.username}"/>
                <L7p:MaxConcurrency stringValue="3"/>
                <L7p:MaxRequestsPerSecond stringValue="10"/>
                <L7p:SplitConcurrencyLimitAcrossNodes booleanValue="false"/>
                <L7p:SplitRateLimitAcrossNodes booleanValue="false"/>
                <L7p:WindowSizeInSeconds stringValue="10"/>
            </L7p:RateLimit>
            <wsp:All wsp:Usage="Required">
                <L7p:CustomizeErrorResponse>
                    <L7p:Content stringValueReference="inline"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Body>
        <soapenv:Fault>
            <faultcode>soapenv:Client</faultcode>
            <faultstring>Too Many Requests</faultstring>
            <faultactor>${request.url}</faultactor>
            <detail>
                <datetime>${request.time}</datetime>
                <errorcode>429: Too Many Requests</errorcode>
                <message>Your requests to this service have exceeded the premitted rate limit, please wait a few seconds and try your request again.</message>
        </detail>
        </soapenv:Fault>
    </soapenv:Body>
</soapenv:Envelope>]]></L7p:Content>
                    <L7p:ContentType stringValue="text/xml;charset=utf-8"/>
                    <L7p:ExtraHeaders nameValuePairArray="included"/>
                    <L7p:HttpStatus stringValue="429"/>
                </L7p:CustomizeErrorResponse>
                <L7p:FalseAssertion/>
            </wsp:All>
            <L7p:assertionComment>
                <L7p:Properties mapValue="included">
                    <L7p:entry>
                        <L7p:key stringValue="RIGHT.COMMENT"/>
                        <L7p:value stringValue="// rate limit dos\sniffing protection"/>
                    </L7p:entry>
                </L7p:Properties>
            </L7p:assertionComment>
        </wsp:OneOrMore>
        <wsp:OneOrMore wsp:Usage="Required">
            <wsp:All wsp:Usage="Required">
                <L7p:SetVariable>
                    <L7p:Base64Expression stringValue="JHtyZXF1ZXN0Lmh0dHAucGFyYW1ldGVyLmZyYWdtZW50fQ=="/>
                    <L7p:ContentType stringValue="text/xml; charset=utf-8"/>
                    <L7p:DataType variableDataType="message"/>
                    <L7p:VariableToSet stringValue="fragment"/>
                </L7p:SetVariable>
                <L7p:Regex>
                    <L7p:AutoTarget booleanValue="false"/>
                    <L7p:FindAll booleanValue="true"/>
                    <L7p:OtherTargetMessageVariable stringValue="fragment"/>
                    <L7p:Regex stringValue="\A[a-zA-Z0-9]*\Z"/>
                    <L7p:RegexName stringValue="injection test"/>
                    <L7p:Replacement stringValue=""/>
                    <L7p:Target target="OTHER"/>
                </L7p:Regex>
                <L7p:SetVariable>
                    <L7p:Base64Expression stringValue="JSR7cmVxdWVzdC5odHRwLnBhcmFtZXRlci5mcmFnbWVudH0l"/>
                    <L7p:VariableToSet stringValue="fragment"/>
                </L7p:SetVariable>
            </wsp:All>
            <L7p:SetVariable>
                <L7p:Base64Expression stringValue="JQ=="/>
                <L7p:VariableToSet stringValue="fragment"/>
            </L7p:SetVariable>
            <L7p:assertionComment>
                <L7p:Properties mapValue="included">
                    <L7p:entry>
                        <L7p:key stringValue="RIGHT.COMMENT"/>
                        <L7p:value stringValue="// code\sql injection detection"/>
                    </L7p:entry>
                </L7p:Properties>
            </L7p:assertionComment>
        </wsp:OneOrMore>
        <wsp:OneOrMore wsp:Usage="Required">
            <wsp:All wsp:Usage="Required">
                <L7p:SetVariable>
                    <L7p:Base64Expression stringValue="JHtyZXF1ZXN0Lmh0dHAucGFyYW1ldGVyLm9iamVjdGlkfQ=="/>
                    <L7p:ContentType stringValue="text/xml; charset=utf-8"/>
                    <L7p:DataType variableDataType="message"/>
                    <L7p:VariableToSet stringValue="objectid"/>
                </L7p:SetVariable>
                <L7p:Regex>
                    <L7p:AutoTarget booleanValue="false"/>
                    <L7p:FindAll booleanValue="true"/>
                    <L7p:OtherTargetMessageVariable stringValue="objectid"/>
                    <L7p:Regex stringValue="\A[a-fA-F0-9]*\Z"/>
                    <L7p:RegexName stringValue="injection test"/>
                    <L7p:Replacement stringValue=""/>
                    <L7p:Target target="OTHER"/>
                </L7p:Regex>
                <L7p:SetVariable>
                    <L7p:Base64Expression stringValue="JSR7cmVxdWVzdC5odHRwLnBhcmFtZXRlci5vYmplY3RpZH0l"/>
                    <L7p:VariableToSet stringValue="objectid"/>
                </L7p:SetVariable>
            </wsp:All>
            <L7p:SetVariable>
                <L7p:Base64Expression stringValue="JQ=="/>
                <L7p:VariableToSet stringValue="objectid"/>
            </L7p:SetVariable>
            <L7p:assertionComment>
                <L7p:Properties mapValue="included">
                    <L7p:entry>
                        <L7p:key stringValue="RIGHT.COMMENT"/>
                        <L7p:value stringValue="// code\sql injection detection"/>
                    </L7p:entry>
                </L7p:Properties>
            </L7p:assertionComment>
        </wsp:OneOrMore>
        <wsp:OneOrMore wsp:Usage="Required">
            <wsp:All wsp:Usage="Required">
                <wsp:OneOrMore wsp:Usage="Required">
                    <L7p:ComparisonAssertion>
                        <L7p:CaseSensitive booleanValue="false"/>
                        <L7p:Expression1 stringValue="${fragment}"/>
                        <L7p:MultivaluedComparison multivaluedComparison="FAIL"/>
                        <L7p:Operator operatorNull="null"/>
                        <L7p:Predicates predicates="included">
                            <L7p:item dataType="included">
                                <L7p:Type variableDataType="string"/>
                            </L7p:item>
                            <L7p:item binary="included">
                                <L7p:CaseSensitive booleanValue="false"/>
                                <L7p:Negated booleanValue="true"/>
                                <L7p:RightValue stringValue="%"/>
                            </L7p:item>
                        </L7p:Predicates>
                    </L7p:ComparisonAssertion>
                    <L7p:ComparisonAssertion>
                        <L7p:CaseSensitive booleanValue="false"/>
                        <L7p:Expression1 stringValue="${objectid}"/>
                        <L7p:MultivaluedComparison multivaluedComparison="FAIL"/>
                        <L7p:Operator operatorNull="null"/>
                        <L7p:Predicates predicates="included">
                            <L7p:item dataType="included">
                                <L7p:Type variableDataType="string"/>
                            </L7p:item>
                            <L7p:item binary="included">
                                <L7p:CaseSensitive booleanValue="false"/>
                                <L7p:Negated booleanValue="true"/>
                                <L7p:RightValue stringValue="%"/>
                            </L7p:item>
                        </L7p:Predicates>
                    </L7p:ComparisonAssertion>
                </wsp:OneOrMore>
                <L7p:SetVariable>
                    <L7p:Base64Expression stringValue="PGh0bWw+PGJvZHk+PHRhYmxlIGJvcmRlcj4NCjx0ciBhbGlnbj1jZW50ZXIgdmFsaWduPW1pZGRsZT48dGQ+T2JqZWN0aWQ8L3RkPjx0ZD5TZXJ2aWNlPC90ZD48dGQ+Um91dGluZyBVUkk8L3RkPjwvdHI+"/>
                    <L7p:VariableToSet stringValue="csv"/>
                </L7p:SetVariable>
                <L7p:AuditDetailAssertion>
                    <L7p:Detail stringValueReference="inline"><![CDATA[SELECT hex(s.goid) as objectid, s.name, s.routing_uri, s.disabled,
       case when v.xml regexp concat('<L7p:Enabled booleanValue="false"/>\n[ ]*<L7p:PolicyGuid stringValue="',
                        (SELECT guid
                         FROM ssg.policy
                         WHERE policy_type = 'include_fragment'
                           AND name like '${fragment}'
                           AND hex(goid) like '${objectid}'),
         '"/>')
            then 1
            else 0
       end as commented
FROM ssg.published_service s inner join
     ssg.policy_version v on (s.policy_goid = v.policy_goid)
WHERE v.active = 1
  AND v.xml like concat('%<L7p:PolicyGuid stringValue="',
                        (SELECT guid
                         FROM ssg.policy
                         WHERE policy_type = 'include_fragment'
                           AND name like '${fragment}'
                           AND hex(goid) like '${objectid}'),
         '"/>%')
ORDER BY s.name, s.routing_uri, s.goid;]]></L7p:Detail>
                </L7p:AuditDetailAssertion>
                <L7p:JdbcQuery>
                    <L7p:AssertionFailureEnabled booleanValue="false"/>
                    <L7p:ConnectionName stringValue="SSG"/>
                    <L7p:MaxRecords intValue="1000"/>
                    <L7p:NamingMap mapValue="included">
                        <L7p:entry>
                            <L7p:key stringValue="commented"/>
                            <L7p:value stringValue="commented"/>
                        </L7p:entry>
                        <L7p:entry>
                            <L7p:key stringValue="disabled"/>
                            <L7p:value stringValue="disabled"/>
                        </L7p:entry>
                        <L7p:entry>
                            <L7p:key stringValue="name"/>
                            <L7p:value stringValue="name"/>
                        </L7p:entry>
                        <L7p:entry>
                            <L7p:key stringValue="objectid"/>
                            <L7p:value stringValue="objectid"/>
                        </L7p:entry>
                        <L7p:entry>
                            <L7p:key stringValue="routing_uri"/>
                            <L7p:value stringValue="routing_uri"/>
                        </L7p:entry>
                    </L7p:NamingMap>
                    <L7p:SqlQuery stringValueReference="inline"><![CDATA[SELECT hex(s.goid) as objectid, s.name, s.routing_uri, s.disabled,
       case when v.xml not regexp concat('<L7p:Enabled booleanValue="false"/>\n[ ]*<L7p:PolicyGuid stringValue="',
                        (SELECT guid
                         FROM ssg.policy
                         WHERE policy_type = 'include_fragment'
                           AND name like ${fragment}
                           AND hex(goid) like ${objectid}),
         '"/>')
            then 0
            else 1
       end as commented
FROM ssg.published_service s inner join
     ssg.policy_version v on (s.policy_goid = v.policy_goid)
WHERE v.active = 1
  AND v.xml like concat('%<L7p:PolicyGuid stringValue="',
                        (SELECT guid
                         FROM ssg.policy
                         WHERE policy_type = 'include_fragment'
                           AND name like ${fragment}
                           AND hex(goid) like ${objectid}),
         '"/>%')
ORDER BY s.name, s.routing_uri, s.goid;]]></L7p:SqlQuery>
                    <L7p:VariablePrefix stringValue="references"/>
                </L7p:JdbcQuery>
                <L7p:ForEachLoop L7p:Usage="Required"
                    loopVariable="references.objectid" variablePrefix="service">
                    <wsp:All wsp:Usage="Required">
                        <L7p:ItemLookupByIndex>
                            <L7p:IndexValue stringValue="${service.iterations}"/>
                            <L7p:MultivaluedVariableName stringValue="references.objectid"/>
                            <L7p:OutputVariableName stringValue="objectid"/>
                        </L7p:ItemLookupByIndex>
                        <L7p:ItemLookupByIndex>
                            <L7p:IndexValue stringValue="${service.iterations}"/>
                            <L7p:MultivaluedVariableName stringValue="references.name"/>
                            <L7p:OutputVariableName stringValue="name"/>
                        </L7p:ItemLookupByIndex>
                        <L7p:ItemLookupByIndex>
                            <L7p:IndexValue stringValue="${service.iterations}"/>
                            <L7p:MultivaluedVariableName stringValue="references.routing_uri"/>
                            <L7p:OutputVariableName stringValue="routing_uri"/>
                        </L7p:ItemLookupByIndex>
                        <L7p:ItemLookupByIndex>
                            <L7p:IndexValue stringValue="${service.iterations}"/>
                            <L7p:MultivaluedVariableName stringValue="references.disabled"/>
                            <L7p:OutputVariableName stringValue="disabled"/>
                        </L7p:ItemLookupByIndex>
                        <L7p:ItemLookupByIndex>
                            <L7p:IndexValue stringValue="${service.iterations}"/>
                            <L7p:MultivaluedVariableName stringValue="references.commented"/>
                            <L7p:OutputVariableName stringValue="commented"/>
                        </L7p:ItemLookupByIndex>
                        <L7p:assertionComment>
                            <L7p:Properties mapValue="included">
                                <L7p:entry>
                                    <L7p:key stringValue="RIGHT.COMMENT"/>
                                    <L7p:value stringValue="//map policy properties"/>
                                </L7p:entry>
                            </L7p:Properties>
                        </L7p:assertionComment>
                    </wsp:All>
                    <L7p:SetVariable>
                        <L7p:Base64Expression stringValue="PHRy"/>
                        <L7p:VariableToSet stringValue="service"/>
                    </L7p:SetVariable>
                    <wsp:OneOrMore wsp:Usage="Required">
                        <L7p:ComparisonAssertion>
                            <L7p:CaseSensitive booleanValue="false"/>
                            <L7p:Expression1 stringValue="${disabled}"/>
                            <L7p:Expression2 stringValue="0"/>
                            <L7p:Predicates predicates="included">
                                <L7p:item binary="included">
                                    <L7p:CaseSensitive booleanValue="false"/>
                                    <L7p:RightValue stringValue="0"/>
                                </L7p:item>
                            </L7p:Predicates>
                        </L7p:ComparisonAssertion>
                        <L7p:SetVariable>
                            <L7p:Base64Expression stringValue="JHtzZXJ2aWNlfSBiZ2NvbG9yPSJBQUFBQUEi"/>
                            <L7p:VariableToSet stringValue="service"/>
                        </L7p:SetVariable>
                        <L7p:assertionComment>
                            <L7p:Properties mapValue="included">
                                <L7p:entry>
                                    <L7p:key stringValue="RIGHT.COMMENT"/>
                                    <L7p:value stringValue="//gray out disabled services"/>
                                </L7p:entry>
                            </L7p:Properties>
                        </L7p:assertionComment>
                    </wsp:OneOrMore>
                    <L7p:SetVariable>
                        <L7p:Base64Expression stringValue="JHtzZXJ2aWNlfT48dGQgbm93cmFwPiR7b2JqZWN0aWR9PC90ZD48dGQgbm93cmFwPg=="/>
                        <L7p:VariableToSet stringValue="service"/>
                    </L7p:SetVariable>
                    <wsp:OneOrMore wsp:Usage="Required">
                        <wsp:All wsp:Usage="Required">
                            <L7p:ComparisonAssertion>
                                <L7p:CaseSensitive booleanValue="false"/>
                                <L7p:Expression1 stringValue="${commented}"/>
                                <L7p:Expression2 stringValue="0"/>
                                <L7p:Predicates predicates="included">
                                    <L7p:item binary="included">
                                    <L7p:CaseSensitive booleanValue="false"/>
                                    <L7p:RightValue stringValue="0"/>
                                    </L7p:item>
                                </L7p:Predicates>
                            </L7p:ComparisonAssertion>
                            <L7p:SetVariable>
                                <L7p:Base64Expression stringValue="JHtzZXJ2aWNlfSR7bmFtZX0="/>
                                <L7p:VariableToSet stringValue="service"/>
                            </L7p:SetVariable>
                        </wsp:All>
                        <L7p:SetVariable>
                            <L7p:Base64Expression stringValue="JHtzZXJ2aWNlfTxmb250IGNvbG9yPSJDQzExMDAiPiR7bmFtZX08L2ZvbnQ+"/>
                            <L7p:VariableToSet stringValue="service"/>
                        </L7p:SetVariable>
                        <L7p:assertionComment>
                            <L7p:Properties mapValue="included">
                                <L7p:entry>
                                    <L7p:key stringValue="RIGHT.COMMENT"/>
                                    <L7p:value stringValue="//red text disabled assertions"/>
                                </L7p:entry>
                            </L7p:Properties>
                        </L7p:assertionComment>
                    </wsp:OneOrMore>
                    <L7p:SetVariable>
                        <L7p:Base64Expression stringValue="JHtzZXJ2aWNlfTwvdGQ+PHRkIG5vd3JhcD4ke3JvdXRpbmdfdXJpfTwvdGQ+PC90ZD48L3RyPg=="/>
                        <L7p:VariableToSet stringValue="service"/>
                    </L7p:SetVariable>
                    <L7p:SetVariable>
                        <L7p:Base64Expression stringValue="JHtjc3Z9DQoke3NlcnZpY2V9"/>
                        <L7p:VariableToSet stringValue="csv"/>
                    </L7p:SetVariable>
                </L7p:ForEachLoop>
                <L7p:SetVariable>
                    <L7p:Base64Expression stringValue="JHtjc3Z9DQo8L3RhYmxlPg0KUm93cyBpbiBncmF5IGFyZSBkaXNhYmxlZCBzZXJ2aWNlcy4NCk5hbWVzIGluIHJlZCBhcmUgc2VydmljZXMgaW4gd2hpY2ggdGhlIHJlZmVyZW5jZWQgZnJhZ21lbnQgaW5jbHVkZSBhc3NlcnRpb24gaXMgZGlzYWJsZWQuPC9ib2R5PjwvaHRtbD4="/>
                    <L7p:VariableToSet stringValue="csv"/>
                </L7p:SetVariable>
                <L7p:assertionComment>
                    <L7p:Properties mapValue="included">
                        <L7p:entry>
                            <L7p:key stringValue="RIGHT.COMMENT"/>
                            <L7p:value stringValue="// list services that contain requested fragment"/>
                        </L7p:entry>
                    </L7p:Properties>
                </L7p:assertionComment>
            </wsp:All>
            <wsp:All wsp:Usage="Required">
                <L7p:SetVariable>
                    <L7p:Base64Expression stringValue="PGh0bWw+PGJvZHk+PHRhYmxlIGJvcmRlcj4NCjx0ciBhbGlnbj1jZW50ZXIgdmFsaWduPW1pZGRsZT48dGQ+T2JqZWN0aWQ8L3RkPjx0ZD5TZXJ2aWNlPC90ZD48L3RyPg=="/>
                    <L7p:VariableToSet stringValue="csv"/>
                </L7p:SetVariable>
                <L7p:SetVariable>
                    <L7p:Base64Expression stringValue="VG8gZ2V0IGEgbGlzdGluZyBvZiBzZXJ2aWNlcyByZWZlcmVuY2VpbmcgYSBnaXZlbiBmcmFnbWVudCBjYWxsIHRoaXMgc2VydmljZSB3aXRoIHRoZSBwYXJhbWV0ZXIgP2ZyYWdtZW50PVtuYW1lXSB3aGVyZSBbbmFtZV0gaXMgdGhlIGZyYWdtZW50IHRoYXQgeW91IHdhbnQgdGhlIGxpc3Qgb2Ygc2VydmljZXMgdGhhdCBhcmUgbWFraW5nIHVzZSBvZiB0aGF0IGZyYWdtZW50Lg0KIA0KJHtjc3Z9"/>
                    <L7p:VariableToSet stringValue="csv"/>
                </L7p:SetVariable>
                <L7p:AuditDetailAssertion>
                    <L7p:Detail stringValueReference="inline"><![CDATA[SELECT hex(goid) as objectid, name
FROM ssg.policy
WHERE policy_type = 'include_fragment'
ORDER BY name, goid;]]></L7p:Detail>
                </L7p:AuditDetailAssertion>
                <L7p:JdbcQuery>
                    <L7p:AssertionFailureEnabled booleanValue="false"/>
                    <L7p:ConnectionName stringValue="SSG"/>
                    <L7p:MaxRecords intValue="1000"/>
                    <L7p:NamingMap mapValue="included">
                        <L7p:entry>
                            <L7p:key stringValue="name"/>
                            <L7p:value stringValue="name"/>
                        </L7p:entry>
                        <L7p:entry>
                            <L7p:key stringValue="objectid"/>
                            <L7p:value stringValue="objectid"/>
                        </L7p:entry>
                    </L7p:NamingMap>
                    <L7p:SqlQuery stringValueReference="inline"><![CDATA[SELECT hex(goid) as objectid, name
FROM ssg.policy
WHERE policy_type = 'include_fragment'
ORDER BY name, goid;]]></L7p:SqlQuery>
                    <L7p:VariablePrefix stringValue="fragments"/>
                </L7p:JdbcQuery>
                <L7p:ForEachLoop L7p:Usage="Required"
                    loopVariable="fragments.objectid" variablePrefix="service">
                    <L7p:SetVariable>
                        <L7p:Base64Expression stringValue="PHRyPg=="/>
                        <L7p:VariableToSet stringValue="service"/>
                    </L7p:SetVariable>
                    <wsp:All wsp:Usage="Required">
                        <L7p:ItemLookupByIndex>
                            <L7p:IndexValue stringValue="${service.iterations}"/>
                            <L7p:MultivaluedVariableName stringValue="fragments.objectid"/>
                            <L7p:OutputVariableName stringValue="objectid"/>
                        </L7p:ItemLookupByIndex>
                        <L7p:ItemLookupByIndex>
                            <L7p:IndexValue stringValue="${service.iterations}"/>
                            <L7p:MultivaluedVariableName stringValue="fragments.name"/>
                            <L7p:OutputVariableName stringValue="name"/>
                        </L7p:ItemLookupByIndex>
                        <L7p:SetVariable>
                            <L7p:Base64Expression stringValue="JHtzZXJ2aWNlfTx0ZCBub3dyYXA+JHtvYmplY3RpZH08L3RkPjx0ZCBub3dyYXA+JHtuYW1lfTwvdGQ+PC90ZD4="/>
                            <L7p:VariableToSet stringValue="service"/>
                        </L7p:SetVariable>
                        <L7p:assertionComment>
                            <L7p:Properties mapValue="included">
                                <L7p:entry>
                                    <L7p:key stringValue="RIGHT.COMMENT"/>
                                    <L7p:value stringValue="//map policy properties"/>
                                </L7p:entry>
                            </L7p:Properties>
                        </L7p:assertionComment>
                    </wsp:All>
                    <L7p:SetVariable>
                        <L7p:Base64Expression stringValue="JHtzZXJ2aWNlfTwvdHI+"/>
                        <L7p:VariableToSet stringValue="service"/>
                    </L7p:SetVariable>
                    <L7p:SetVariable>
                        <L7p:Base64Expression stringValue="JHtjc3Z9DQoke3NlcnZpY2V9"/>
                        <L7p:VariableToSet stringValue="csv"/>
                    </L7p:SetVariable>
                </L7p:ForEachLoop>
                <L7p:SetVariable>
                    <L7p:Base64Expression stringValue="JHtjc3Z9DQo8L3RhYmxlPjwvYm9keT48L2h0bWw+"/>
                    <L7p:VariableToSet stringValue="csv"/>
                </L7p:SetVariable>
                <L7p:assertionComment>
                    <L7p:Properties mapValue="included">
                        <L7p:entry>
                            <L7p:key stringValue="RIGHT.COMMENT"/>
                            <L7p:value stringValue="// list fragments"/>
                        </L7p:entry>
                    </L7p:Properties>
                </L7p:assertionComment>
            </wsp:All>
            <L7p:assertionComment>
                <L7p:Properties mapValue="included">
                    <L7p:entry>
                        <L7p:key stringValue="RIGHT.COMMENT"/>
                        <L7p:value stringValue="// build table of services or fragments"/>
                    </L7p:entry>
                </L7p:Properties>
            </L7p:assertionComment>
        </wsp:OneOrMore>
        <L7p:HardcodedResponse>
            <L7p:Base64ResponseBody stringValue="JHtjc3Z9"/>
            <L7p:ResponseContentType stringValue="text/html; charset=utf-8"/>
        </L7p:HardcodedResponse>
    </wsp:All>
</wsp:Policy>