Skip to content

Commit 8770167

Browse files
Merge pull request #34 from Nictiz/UseQualificationTokensJSON
Use qualification tokens json
2 parents b35d419 + 6d2acd0 commit 8770167

File tree

6 files changed

+214
-22
lines changed

6 files changed

+214
-22
lines changed

generate/README.md

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -204,30 +204,51 @@ It is also possible implicitly declare the rule when it is used by adding the `h
204204
</assert>
205205
```
206206

207-
### Patient token and date T
207+
### Date T and authorization headers
208208

209-
There are two special elements for use cases that are common across Nictiz test scripts.
209+
There are special elements for two use cases that are common across Nictiz test scripts.
210210

211-
The first one for including the patient authorization token in the TestScript:
211+
The first one is to indicate that the "date T" variable should be defined for the TestScript:
212212

213213
```xml
214-
<nts:patientTokenFixture href="..">
214+
<nts:includeDateT value="yes|no">
215215
```
216216

217-
The `href` attribute should point to the `Patient` instance containing the token, as is commonly done with the Nictiz test scripts, placed in the "_reference"-folder. The `nts:scenario` attribute on the TestScript root determines how this tag is expanded:
217+
If this element is present, and `value` is absent or set to "yes", a variable for setting date T will be included in the TestScript.
218218

219-
* for "server", a variable will be created which the test script executor can set, defaulting to the value from the fixture.
220-
* for "client", the fixture will be included and a variable called "patient-token-id" will be created that reads the value from the fixture
219+
The second one deals with the authorization header for defining the patient context in the TestScript. The assumption here is that the (static) content of an `Authorization` header associated with a specific Patient resource `.id` is defined in a JSON file with the following syntax:
220+
```json
221+
{
222+
"accessToken": "Bearer ...",
223+
"resourceId": "[resource.id of Patient resource]",
224+
}
225+
```
221226

222-
The token filename should end with `token.xml` and the token id should start with `Bearer`.
227+
This file should be passed as the `tokens.json` parameter to the build script. The token can then be imported into a TestScript using:
223228

224-
The second element is to indicate that the "date T" variable should be defined for the testscript:
229+
```xml
230+
<nts:authToken patientResourceId="[resource.id of Patient resource]" {id="[patient-token-id]"}/>
231+
```
232+
233+
This sets an NTS parameter with the specified `id`, which can then be used throughout the NTS file. `id` is usually omitted, in which case it defaults to "patient-token-id".
225234

235+
For example, if you included a token with id "patient-token-id", you can use it to define the Authorization header with:
226236
```xml
227-
<nts:includeDateT value="yes|no">
237+
<requestHeader>
238+
<field value="Authorization"/>
239+
<value value="{$patient-token}"/>
240+
</requestHeader>
228241
```
229242

230-
If this element is present, and `value` is absent or set to "yes", a variable for setting date T will be included in the TestScript.
243+
The output depends on `nts:scenario`. For client scripts, the content of the access token will be hardcoded in the TestScript output. For server scripts, a TestScript variable will be defined that defaults to the access token, but which can be overruled by the tester. The NTS variable will be translated to this TestScript variable.
244+
245+
There is actually a second (outdated) mechanism to import authorization tokens:
246+
247+
```xml
248+
<nts:patientTokenFixture href="..">
249+
```
250+
251+
The `href` attribute should point to a `Patient` instance containing the content of the authorization header as its `.id`, placed in the "_reference"-folder and with a file name ending in `-token.xml`. This will always result in definig the TestScript variable `patient-token-id`, for both client and server scripts.
231252

232253
### Scenario: server (xis) or client (phr)
233254

@@ -357,6 +378,12 @@ Because of the verbosity of the ANT build, the logging level is set to 1 (warnin
357378

358379
## Changelog
359380

381+
### 2.5.0
382+
- Add the tag `<nts:authToken/>` to work with authorization tokens defined in a JSON file, as is expected for mock authentication on Touchstone. This supersedes the `<nts:patientTokenFixture/>` tag.
383+
384+
### 2.4.1
385+
- Make the magic _FORMAT parameter available to nts:ifset
386+
360387
### 2.4.0
361388
- Add an extra script to convert XML fixtures to JSON. This can be used separately or in conjunction with the NTS build script.
362389

generate/ant/build-multiple.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
<property name="lib.dir" value="${lib.dir}"/>
2727
<property name="commoncomponents.dir" value="${commoncomponents.dir}"/>
2828
<property name="version.addition" value="${version.addition}"/>
29+
<property name="tokens.json" value="${tokens.json}"/>
2930
<property name="convert.to.json.file" value="${convert.to.json.file}"/>
3031
</ant>
3132
</sequential>

generate/ant/build.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
- lib.dir : The directory where all build dependency's will be placed. It's a good idea to add this to
1818
.gitignore.
1919
- [components.dir] : Optional - the directory containing the project components, relative to input.dir. Defaults to '_components'.
20+
- [tokens.json] : Optional - the relative path to a JSON file linking Patient resource id's to authorization tokens. This is a feature specifically for the mocked authorization mechanism on Touchstone.
2021
- [loadresources.exclude] : Optional - A relative path to a folder containing the fixtures or to specific filenames to be excluded from
2122
the LoadResources script. Multiple entries can be comma separated. `*` is accepted as a wildcard.
2223
- [processfixtures.skip] : Optional - If 'true' (or any other non-empty value) processing fixtures is skipped.
@@ -54,6 +55,12 @@
5455
<property name="commoncomponents.dir.abs" location="${commoncomponents.dir}"/>
5556
<property name="reference.subdir" value="_reference"/>
5657

58+
<!-- Construct a file URL to the tokens JSON file. -->
59+
<pathconvert property="tokens.json.url" targetos="unix">
60+
<path location="${tokens.json}"/>
61+
<mapper type="regexp" from="(.*)" to="file:/\1"/>
62+
</pathconvert>
63+
5764
<!-- Try to read all project property's defined in build.properties -->
5865
<property file="${input.dir.abs}/build.properties"/>
5966

@@ -236,6 +243,7 @@
236243
<param name="expectedResponseFormat" expression="@{expectedResponseFormat}"/>
237244
<param name="target" expression="@{target}"/>
238245
<param name="versionAddition" expression="${version.addition}"/>
246+
<param name="tokensJsonFile" expression="${tokens.json.url}"/>
239247
</parameters>
240248
</saxon-transform>
241249

@@ -253,6 +261,7 @@
253261
<param name="projectComponentFolder" expression="${components.dir.abs}"/>
254262
<param name="target" expression="@{target}"/>
255263
<param name="versionAddition" expression="${version.addition}"/>
264+
<param name="tokensJsonFile" expression="${tokens.json.url}"/>
256265
</parameters>
257266
</saxon-transform>
258267
<collect-references testscript.path="@{output.dir}/${nts.file.newname}" references.file="@{references.file}" reference.dir.rel="@{reference.dir.rel}"/>
@@ -395,6 +404,7 @@
395404
<param name="referenceBase" expression="${reference.dir.loadresourcesrelative.normalized}"/>
396405
<param name="referenceDir" expression="${input.dir.abs}/${reference.subdir}/"/>
397406
<param name="loadResourcesExclude" expression="${loadresources.exclude}"/>
407+
<param name="tokensJsonFile" expression="${tokens.json.url}"/>
398408
</parameters>
399409
</saxon-transform>
400410

generate/xslt/generateLoadResources.xsl

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" xmlns:f="http://hl7.org/fhir" exclude-result-prefixes="#all" version="2.0">
2+
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
3+
xmlns:xs="http://www.w3.org/2001/XMLSchema"
4+
xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl"
5+
xmlns:f="http://hl7.org/fhir"
6+
xmlns:nts="http://nictiz.nl/xsl/testscript"
7+
exclude-result-prefixes="#all" version="2.0">
38
<!-- Stylesheet to write out the special TestScript resource that is used to load all fixtures to the test
49
server (the load script) -->
510

@@ -14,6 +19,10 @@
1419
<!-- Comma-separated list of paths to exclude -->
1520
<xsl:param name="loadResourcesExclude"/>
1621

22+
<!-- Include the machinery to resolve auth tokens from a JSON file. This adds the parameter tokensJSONFile, which
23+
should hold an URL. -->
24+
<xsl:include href="resolveAuthTokens.xsl"/>
25+
1726
<xsl:template match="/">
1827

1928
<!-- Convert the reference to a file:// URL and make sure it ends with a slash. -->
@@ -59,9 +68,6 @@
5968
</xsl:choose>
6069
</xsl:variable>
6170

62-
<!-- And collect all bearer fixtures as file URLs -->
63-
<xsl:variable name="tokens" select="collection(iri-to-uri(concat(resolve-uri($referenceDirAsUrl), '?select=', '*token.xml;recurse=yes')))/f:*"/>
64-
6571
<xsl:choose>
6672
<xsl:when test="$fixtures">
6773
<!-- Write out the TestScript resource -->
@@ -117,9 +123,38 @@
117123
<description value="Date that data and queries are expected to be relative to."/>
118124
</variable>
119125

126+
<xsl:variable name="tokens" as="element(nts:authToken)*">
127+
<xsl:variable name="tokensCached" as="element(nts:authToken)*">
128+
<!-- Collect all Patient resources that exist or are referred from other resources -->
129+
<xsl:variable name="patientReferences" as="xs:string*">
130+
<xsl:for-each select="$fixtures[local-name() = 'Patient']">
131+
<xsl:value-of select="./f:id/@value"/>
132+
</xsl:for-each>
133+
<xsl:for-each select="$fixtures//f:reference[starts-with(@value, 'Patient/')]">
134+
<xsl:value-of select="substring(./@value, 9)"/>
135+
</xsl:for-each>
136+
</xsl:variable>
137+
<!-- ... and find the matching tokens, if they exists in the JSON file. -->
138+
<xsl:for-each select="distinct-values($patientReferences)">
139+
<xsl:copy-of select="nts:resolveAuthToken(., '', false())"/>
140+
</xsl:for-each>
141+
142+
<!-- Add to this the tokens from token files (where the resource id's are extracted from
143+
the file names. -->
144+
<xsl:for-each select="collection(iri-to-uri(concat(resolve-uri($referenceDirAsUrl), '?select=', '*token.xml;recurse=yes')))">
145+
<nts:authToken patientResourceId="{tokenize(substring-before(base-uri(), '-token.xml'), '/')[last()]}" token="{.//f:id/@value}"/>
146+
</xsl:for-each>
147+
</xsl:variable>
148+
149+
<!-- Make everything unique by token -->
150+
<xsl:for-each-group select="$tokensCached" group-by="./@token">
151+
<xsl:copy-of select="current-group()[1]"/>
152+
</xsl:for-each-group>
153+
</xsl:variable>
154+
120155
<!-- Purge Patients in setup -->
121156
<setup>
122-
<xsl:for-each select="$tokens">
157+
<xsl:for-each select="$tokens[@token]">
123158
<action>
124159
<operation>
125160
<type>
@@ -130,10 +165,10 @@
130165
<accept value="xml"/>
131166
<contentType value="xml"/>
132167
<encodeRequestUrl value="true"/>
133-
<params value="{tokenize(substring-before(base-uri(), '-token.xml'), '/')[last()]}/$purge"/>
168+
<params value="{./@patientResourceId}/$purge"/>
134169
<requestHeader>
135170
<field value="Authorization"/>
136-
<value value="{f:id/@value}"/>
171+
<value value="{./@token}"/>
137172
</requestHeader>
138173
</operation>
139174
</action>
@@ -177,12 +212,12 @@
177212
<field value="Authorization"/>
178213
<!-- KT-330: In MedMij R4, it is required to use the correct patient token for updateCreate of Patients, but it doesn't hurt for STU3 -->
179214
<xsl:choose>
180-
<xsl:when test="$tokens[contains(base-uri(), $resourceId)]">
181-
<value value="{$tokens[contains(base-uri(), $resourceId)][1]/f:id/@value}"/>
215+
<xsl:when test="$tokens[@token != '' and @patientResourceId = $resourceId]">
216+
<value value="{$tokens[@token != '' and @patientResourceId = $resourceId]/@token}"/>
182217
</xsl:when>
183218
<xsl:otherwise>
184219
<!-- Use first patient token, or should we check fixture .subject to determine correct token? -->
185-
<value value="{$tokens[1]/f:id/@value}"/>
220+
<value value="{$tokens[@token != ''][1]/@token}"/>
186221
</xsl:otherwise>
187222
</xsl:choose>
188223
</requestHeader>

generate/xslt/generateTestScript.xsl

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
xmlns="http://hl7.org/fhir"
33
xmlns:f="http://hl7.org/fhir"
44
xmlns:xs="http://www.w3.org/2001/XMLSchema"
5+
xmlns:fn="http://www.w3.org/2005/xpath-functions"
6+
xmlns:array="http://www.w3.org/2005/xpath-functions/array"
7+
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
58
xmlns:nts="http://nictiz.nl/xsl/testscript"
69
exclude-result-prefixes="#all">
710
<xsl:output method="xml" indent="yes"/>
@@ -29,6 +32,10 @@
2932
<!-- Optional string that will be appended verbatim to the verson string. If there is no version element in the
3033
input, it will be set to this parameter. -->
3134
<xsl:param name="versionAddition" select="''"/>
35+
36+
<!-- Include the machinery to resolve auth tokens from a JSON file. This adds the parameter tokensJSONFile, which
37+
should hold an URL. -->
38+
<xsl:include href="resolveAuthTokens.xsl"/>
3239

3340
<!-- The main template, which will call the remaining templates. -->
3441
<xsl:template name="generate" match="f:TestScript">
@@ -47,13 +54,46 @@
4754
<xsl:if test="$scenario = 'server' and not($expectedResponseFormat = ('xml', 'json'))">
4855
<xsl:message terminate="yes" select="concat('Invalid value ''', $expectedResponseFormat, ''' for parameter ''expectedResponseFormat''; should be either ''xml'' or ''json''')"></xsl:message>
4956
</xsl:if>
57+
58+
<!-- Extract the authorization tokens specified using the nts:authToken element(s). These tokens can then be used within
59+
the nts:authHeader element, referenced by their id. -->
60+
<xsl:if test="count(//nts:authToken[@patientResourceId]) &gt; 0 and not($tokensJsonFile)">
61+
<xsl:message terminate="yes">If you use the nts:authToken element, you need to pass in a file containing the tokens using the tokensJsonFile parameter.</xsl:message>
62+
</xsl:if>
63+
<xsl:if test="count(//nts:authToken[not(@id)]) &gt; 1">
64+
<xsl:message terminate="yes">When using multiple nts:authToken elements, at most one may have the default id. All other instances must be uniquely identified with an id.</xsl:message>
65+
</xsl:if>
66+
<xsl:variable name="authTokens" as="element(nts:authToken)*">
67+
<xsl:for-each select="//nts:authToken[@patientResourceId]">
68+
<xsl:variable name="id" select="if (.[@id]) then ./@id else 'patient-token-id'"/>
69+
<xsl:copy-of select="nts:resolveAuthToken(./@patientResourceId, $id, true())"/>
70+
</xsl:for-each>
71+
</xsl:variable>
72+
73+
<!-- Seed the parameters used during expansion with the id's of nts:authToken declarations.
74+
The value of these "magic" parameters depend on the scenario. For server scripts, this will be expanded
75+
to a corresponding TestScript variable. For client scripts, this will contain the literal content of the
76+
token. -->
77+
<xsl:variable name="inclusionParameters" as="element(nts:with-parameter)*">
78+
<xsl:for-each select="$authTokens">
79+
<xsl:if test="$scenario = 'server'">
80+
<nts:with-parameter name="{./@id}" value="{concat('${', ./@id, '}')}"/>
81+
</xsl:if>
82+
<xsl:if test="$scenario = 'client'">
83+
<nts:with-parameter name="{./@id}" value="{./@token}"/>
84+
</xsl:if>
85+
</xsl:for-each>
86+
</xsl:variable>
87+
5088

5189
<!-- Expand all the Nictiz inclusion elements to their FHIR representation -->
5290
<xsl:variable name="expanded">
5391
<xsl:apply-templates mode="expand" select=".">
5492
<xsl:with-param name="scenario" select="$scenario" tunnel="yes"/>
5593
<xsl:with-param name="expectedResponseFormat" select="$expectedResponseFormat" tunnel="yes"/>
5694
<xsl:with-param name="basePath" select="$basePath" tunnel="yes"/>
95+
<xsl:with-param name="inclusionParameters" select="$inclusionParameters" tunnel="yes"/>
96+
<xsl:with-param name="authTokens" select="$authTokens" tunnel="yes"/>
5797
</xsl:apply-templates>
5898
</xsl:variable>
5999

@@ -376,6 +416,22 @@
376416
</xsl:choose>
377417
</xsl:template>
378418

419+
<!-- Expand an nts:authToken element. For server scripts, this will result in a variable with a default value which
420+
the tester can override. For client scripts, this doesn't result in any output (but the element is used
421+
beforehand for finding the correct authorization token to use. -->
422+
<xsl:template match="nts:authToken[@patientResourceId]" mode="expand">
423+
<xsl:param name="scenario" tunnel="yes"/>
424+
<xsl:param name="authTokens" tunnel="yes"/>
425+
426+
<xsl:if test="$scenario='server'">
427+
<variable>
428+
<name value="{if (.[@id]) then ./@id else 'patient-token-id'}"/>
429+
<defaultValue value="{$authTokens[@id = ./@id]/@token}"/>
430+
<description value="OAuth Token for current patient"/>
431+
</variable>
432+
</xsl:if>
433+
</xsl:template>
434+
379435
<!-- Expand an nts:patientTokenFixture element to create a variable called 'patient-token-id'. How this is handled
380436
is different for server and client scripts:
381437
- for a server script, it will be provided with a default value read from the fixture, which can be overridden
@@ -694,7 +750,6 @@
694750
<xsl:value-of select="$fullFilename"/>
695751
</xsl:function>
696752

697-
698753
<!-- Construct a file path from the elements.
699754
param base is the folder where the file resides
700755
param filename is the name of the file in the folder including the extension

0 commit comments

Comments
 (0)