Skip to content

Commit

Permalink
[feature] Start of a test application
Browse files Browse the repository at this point in the history
  • Loading branch information
adamretter committed Aug 31, 2023
1 parent b88e6aa commit ca52802
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 0 deletions.
84 changes: 84 additions & 0 deletions src/test/resources/config-exsaml.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<!-- To disable SAML authentication, set @enabled="false" -->
<config enabled="true">

<!-- In SAML terminology, the eXist DB is the "service provider" (SP)
which uses a remote "identity provider" (IDP, eg PingFederate) to
perform user authentication. Both peers are expected to encode their
"entity" names in requests/responses and to validate the peer's entity.
Also the URI endpoints of both peers need to be configured here. -->

<!-- SERVICE PROVIDER CONFIGURATION -->

<!-- sp (service provider) is our local eXist DB -->
<!-- @entity: just a namestring in URI format -->
<!-- @endpoint: our HTTP endpoint to post SAML responses to -->
<!-- @fallback-relaystate: used if IdP does not send a relaystate -->

<!-- SERVICE PROVIDER CONFIGURATION -->
<sp entity="https://service-provider.org" endpoint="http://localhost:8080/exist/apps/myapp/SAML2SP" fallback-relaystate="https://service-provider.org"/>


<!-- IDENTITY PROVIDER -->
<!-- idp (identity provider) is a remote SAML IDP, eg PingFederate -->
<!-- @entity: their namestring in URI format -->
<!-- @endpoint: their HTTP endpoint to send SAML requests to -->
<!-- @accept-unsolicited: enable IDP-initiated SAML -->
<!-- @force-relaystate: force clients to a local endpoint URI -->
<!-- @certfile: required for XML signature validation if sig sent by IDP -->
<!-- @verify-issuer: is a hack to deal with misconfigured IDPs -->

<idp entity="https://saml.example.com/entityid" endpoint="http://localhost:4000/api/saml/sso" accept-unsolicited="false" force-relaystate="" certfile="/usr/local/existdb/exist/cert/sso-prod.crt" verify-issuer="true"/>

<!-- crypto settings -->
<!-- @hmac-key: server-side secret key for HMACs -->
<!-- @hmac-alg: HMAC algorithm -->
<crypto hmac-key="existdb-saml-xquery-integration-test" hmac-alg="HMAC-SHA-256"/>

<!-- token settings. @valid-mins is important here.
This defines how many minutes the local eXist DB will trust a SAML
assertion. Setting this to "0" will force SAML roundtrip for every
request, including images, css etc. This will put load on the IDP and
should be avoided. Reasonable values might be 5-30. -->
<!-- @valid-mins: validity duration of an auth token in minutes -->
<!-- @name: name to store the token into session parameters -->
<token valid-mins="5" name="_token"/>

<!-- credentials for special user "exsaml". This is a privileged user
in group "dba", needed for 2 purposes:
- "dba" privs required to check user exists / create user on the fly
- SAML requires that an SP (= eXist) maintains a collection of SAML
request IDs that it sent, and that this collection is tamperproof.
Only this user has access to the reqids collection. -->
<!-- @username: username of privileged user -->
<!-- @username: username of privileged user -->
<!-- @pass: plaintext password, WILL GO AWAY -->
<exsaml-creds username="exsaml" group="exsaml" pass="exsaml"/>

<!-- settings for dynamic user creation -->
<!-- Since we are using a third party for authentication (SAML IDP), there
is no need to keep users in the local eXist DB. These settings may
be used to create local DB users on the fly, if required. -->
<!-- @create: either "true" (create local DB users) or "false" (do not) -->
<!-- @group: group membership for created users -->
<dynamic-users create="false"/>
<!-- dynamic-users create="true" group="sso-user"/ -->

<!-- group-attribute -->
<!-- This defines a SAML attribute name that is used specify group
membership, if the IDP passes this information as SAML attribute
assertion -->
<group-attribute>sso-user</group-attribute>

<!-- fake IDP for debugging, if no real IDP is available -->
<!-- Should be empty for production use. If this is non-empty AND
idp/@ep above points to the local server, then a fake SAML assertion
is generated without any user/password dialog. -->
<!-- @result: fake result to return, either "true" (auth ok) or "false"
(auth fail) -->
<!-- @minutes-valid: how long the returned SAML assertion is claimed
valid by the IDP -->
<!-- @user: username to return an assertion for -->
<!-- @group: group membership to return for this user -->
<fake-idp/>
<!-- fake-idp result="true" minutes-valid="10" user="sso-user3" group="sso-user"/-->
</config>
63 changes: 63 additions & 0 deletions src/test/resources/myapp/controller.xq
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
xquery version "3.1";

declare namespace exist = "http://exist.sourceforge.net/NS/exist";

(: import exsaml module :)
import module namespace exsaml = "http://exist-db.org/xquery/exsaml" at 'xmldb:///db/system/repo/existdb-saml-xquery-1.7.0-SNAPSHOT/modules/exsaml.xqm';

declare variable $exist:controller external;
declare variable $exist:path external;

(: this is required for SAML so that the IDP response can be rendered as a form
that gets auto-submitted by the user's browser, back to the SP (eXist) :)
declare option exist:serialize "method=html media-type=text/html indent=no";

(: handle SP endpoint to process SAML response in HTTP POST :)
if ($exist:path = "/SAML2SP")
then
let $log := util:log('info', "SAML2SP: processing SAML response")
let $status := exsaml:process-saml-response-post()
let $log := util:log('debug', "endpoint SAML2SP; status: " || $status/@code)
return
if ($status/@code >= 0) then
(: forward to page that was requested by the user :)
let $debug := util:log("info", "Auth success - code " || $status/@code || " - relaystate: " || $status/@relaystate)
return
<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
<redirect url="{$status/@relaystate}"/>
</dispatch>
else
(: if SAML failed, display an error message for now :)
<data>{string($status/@msg) || ": " || string($status/@data)}</data>

(: if logout, invalidate SAML token :)
else if ($exist:path = '/logout')
then
let $_ :=
if (exsaml:is-enabled())
then
exsaml:invalidate-saml-token()
else ()
return
<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
<redirect url="https://www.evolvedbinary.com"/>
</dispatch>

(: if no valid token, redirect to SAML auth :)
else if (exsaml:is-enabled() and not(exsaml:check-valid-saml-token()))
then
let $debug := exsaml:log('info', "controller: no valid token, redirect to SAML auth")
let $return-path := "/exist/apps" || $exist:controller || $exist:path
return
<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
<redirect url="{exsaml:build-authnreq-redir-url($return-path)}">
<set-header name="Cache-Control" value="no-cache, no-store" />
<set-header name="Pragma" value="no-cache" />
</redirect>
</dispatch>

(: We have an existing valid SAML token! :)
else
<ignore xmlns="http://exist.sourceforge.net/NS/exist">
<cache-control cache="no"/>
</ignore>
8 changes: 8 additions & 0 deletions src/test/resources/myapp/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<html>
<head>
<title>My App</title>
</head>
<body>
<h1>Welcome to MyApp</h1>
</body>
</html>

0 comments on commit ca52802

Please sign in to comment.