Skip to content

Commit c891f73

Browse files
authored
Add v2 launch button (#41)
1 parent 91064b0 commit c891f73

File tree

6 files changed

+503
-222
lines changed

6 files changed

+503
-222
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ Now run Go launcher and navigate to "http://localhost:8000/quick-launch?url=" pa
5454
e.g."http://localhost:8000/quick-launch?url=http://localhost:7777/1_0001.json"
5555
```
5656

57+
The optional query parameter `version` can be added to the quick launch url which allows for the launch payload structure to be specified. If the parameter is not set then the default launch payload structure `v2` will be used.
58+
Documentation on the `v2` structure can be found [here](https://github.com/ONSdigital/ons-schema-definitions/blob/v3/docs/rm_to_eq_runner_payload_v2.rst)
59+
```
60+
e.g."http://localhost:8000/quick-launch?url=http://localhost:7777/1_0001.json&version=v1"
61+
```
62+
5763
### Notes
5864
* There are no unit tests yet
5965
* JWT spec based on http://ons-schema-definitions.readthedocs.io/en/latest/jwt_profile.html

authentication/auth.go

Lines changed: 252 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"encoding/pem"
88
"fmt"
99
"io/ioutil"
10+
"math/rand"
1011
"net/http"
1112
"net/url"
1213
"time"
@@ -110,6 +111,7 @@ func loadSigningKey() (*PrivateKeyResult, *KeyLoadError) {
110111
type QuestionnaireSchema struct {
111112
Metadata []Metadata `json:"metadata"`
112113
SchemaName string `json:"schema_name"`
114+
SurveyType string `json:"theme"`
113115
}
114116

115117
// Metadata is a representation of the metadata within the schema with an additional `Default` value
@@ -119,6 +121,59 @@ type Metadata struct {
119121
Default string `json:"default"`
120122
}
121123

124+
func isSurveyMetadata(key string) bool {
125+
switch key {
126+
case
127+
"case_ref",
128+
"case_type",
129+
"display_address",
130+
"employment_date",
131+
"form_type",
132+
"period_id",
133+
"period_str",
134+
"ref_p_end_date",
135+
"ref_p_start_date",
136+
"ru_name",
137+
"ru_ref",
138+
"trad_as",
139+
"user_id",
140+
"qid":
141+
return true
142+
}
143+
return false
144+
}
145+
146+
func isRequiredMetadata(key string) bool {
147+
switch key {
148+
case
149+
"case_id",
150+
"region_code",
151+
"channel",
152+
"language_code",
153+
"collection_exercise_sid",
154+
"response_expires_at",
155+
"response_id",
156+
"schema_name",
157+
"account_service_url":
158+
return true
159+
}
160+
return false
161+
}
162+
163+
func getSurveyMetadataFromClaims(claimValues map[string][]string, data map[string]interface{}, claims map[string]interface{}, surveyMetadata map[string]interface{}) {
164+
for key, value := range claimValues {
165+
if isSurveyMetadata(key) {
166+
data[key] = value[0]
167+
} else if key != "roles" && isRequiredMetadata(key) && value[0] != "" {
168+
claims[key] = value[0]
169+
} else if key == "roles" {
170+
claims[key] = value
171+
}
172+
}
173+
surveyMetadata["data"] = data
174+
claims["survey_metadata"] = surveyMetadata
175+
}
176+
122177
func generateClaims(claimValues map[string][]string, launcherSchema surveys.LauncherSchema) (claims map[string]interface{}) {
123178

124179
var roles []string
@@ -158,6 +213,42 @@ func generateClaims(claimValues map[string][]string, launcherSchema surveys.Laun
158213
return claims
159214
}
160215

216+
func generateClaimsV2(claimValues map[string][]string, launcherSchema surveys.LauncherSchema, schema QuestionnaireSchema) (claims map[string]interface{}) {
217+
218+
var roles []string
219+
if rolesValues, ok := claimValues["roles"]; ok {
220+
roles = rolesValues
221+
} else {
222+
roles = []string{"dumper"}
223+
}
224+
225+
claims = make(map[string]interface{})
226+
227+
claims["roles"] = roles
228+
TxID, _ := uuid.NewV4()
229+
claims["tx_id"] = TxID.String()
230+
claims["version"] = "v2"
231+
232+
surveyMetadata := make(map[string]interface{})
233+
data := make(map[string]interface{})
234+
235+
if schema.SurveyType == "social" || schema.SurveyType == "health" {
236+
receiptingKeys := []string{"qid"}
237+
surveyMetadata["receipting_keys"] = receiptingKeys
238+
}
239+
240+
getSurveyMetadataFromClaims(claimValues, data, claims, surveyMetadata)
241+
242+
// When quicklaunching, schema_name will not be set, but launcherSchema will have the schema_name.
243+
if len(claimValues["schema_name"]) == 0 && launcherSchema.Name != "" {
244+
claims["schema_name"] = launcherSchema.Name
245+
}
246+
247+
log.Printf("Using claims: %s", claims)
248+
249+
return claims
250+
}
251+
161252
// GenerateJwtClaims creates a jwtClaim needed to generate a token
162253
func GenerateJwtClaims() (jwtClaims map[string]interface{}) {
163254
issued := time.Now()
@@ -219,11 +310,10 @@ func launcherSchemaFromURL(url string) (launcherSchema surveys.LauncherSchema, e
219310
schemaName = schema.SchemaName
220311
}
221312

222-
log.Println("Quicklaunch schema_name set to: ", schemaName)
223-
224313
launcherSchema = surveys.LauncherSchema{
225-
URL: url + cacheBust,
226-
Name: schemaName,
314+
URL: url + cacheBust,
315+
Name: schemaName,
316+
SurveyType: schema.SurveyType,
227317
}
228318

229319
return launcherSchema, ""
@@ -388,6 +478,76 @@ func GenerateTokenFromDefaults(schemaURL string, accountServiceURL string, accou
388478
return token, ""
389479
}
390480

481+
// GenerateTokenFromDefaultsV2 coverts a set of DEFAULT values into a JWT
482+
func GenerateTokenFromDefaultsV2(schemaURL string, accountServiceURL string, urlValues url.Values) (token string, error string) {
483+
launcherSchema, validationError := launcherSchemaFromURL(schemaURL)
484+
if validationError != "" {
485+
return "", validationError
486+
}
487+
488+
schema, error := getSchema(launcherSchema)
489+
if error != "" {
490+
return "", fmt.Sprintf("getSchema failed err: %v", error)
491+
}
492+
493+
claims := make(map[string]interface{})
494+
urlValues["account_service_url"] = []string{accountServiceURL}
495+
496+
claims = generateClaimsV2(urlValues, launcherSchema, schema)
497+
498+
requiredMetadata, error := GetRequiredMetadata(launcherSchema)
499+
if error != "" {
500+
return "", fmt.Sprintf("GetRequiredMetadata failed err: %v", error)
501+
}
502+
503+
data := make(map[string]interface{})
504+
505+
for _, metadata := range requiredMetadata {
506+
if metadata.Validator == "boolean" {
507+
data[metadata.Name] = getBooleanOrDefault(metadata.Name, urlValues, false)
508+
509+
continue
510+
}
511+
data[metadata.Name] = getStringOrDefault(metadata.Name, urlValues, metadata.Default)
512+
}
513+
514+
surveyMetadata := make(map[string]interface{})
515+
updatedData := make(map[string]interface{})
516+
517+
if claims["survey_metadata"] != nil {
518+
surveyMetadata = claims["survey_metadata"].(map[string]interface{})
519+
}
520+
for key, value := range data {
521+
updatedData[key] = value
522+
}
523+
524+
initialData := surveyMetadata["data"].(map[string]interface{})
525+
526+
for key, value := range initialData {
527+
updatedData[key] = value
528+
}
529+
530+
surveyMetadata["data"] = updatedData
531+
claims["survey_metadata"] = surveyMetadata
532+
533+
jwtClaims := GenerateJwtClaims()
534+
for key, v := range jwtClaims {
535+
claims[key] = v
536+
}
537+
538+
schemaClaims := getSchemaClaims(launcherSchema)
539+
for key, v := range schemaClaims {
540+
claims[key] = v
541+
}
542+
543+
token, tokenError := generateTokenFromClaims(claims)
544+
if tokenError != nil {
545+
return token, fmt.Sprintf("GenerateTokenFromDefaults failed err: %v", tokenError)
546+
}
547+
548+
return token, ""
549+
}
550+
391551
// TransformSchemaParamsToName Returns a schema name from business schema parameters
392552
func TransformSchemaParamsToName(postValues url.Values) string {
393553
if postValues.Get("schema_name") != "" {
@@ -402,15 +562,26 @@ func TransformSchemaParamsToName(postValues url.Values) string {
402562
}
403563

404564
// GenerateTokenFromPost converts a set of POST values into a JWT
405-
func GenerateTokenFromPost(postValues url.Values) (string, string) {
565+
func GenerateTokenFromPost(postValues url.Values, launchVersion2 bool) (string, string) {
406566
log.Println("POST received: ", postValues)
407567

408568
schemaName := TransformSchemaParamsToName(postValues)
409569
schemaUrl := postValues.Get("schema_url")
410570

411571
launcherSchema := surveys.GetLauncherSchema(schemaName, schemaUrl)
412572

413-
claims := generateClaims(postValues, launcherSchema)
573+
schema, error := getSchema(launcherSchema)
574+
if error != "" {
575+
return "", fmt.Sprintf("getSchema failed err: %v", error)
576+
}
577+
578+
claims := make(map[string]interface{})
579+
580+
if launchVersion2 {
581+
claims = generateClaimsV2(postValues, launcherSchema, schema)
582+
} else {
583+
claims = generateClaims(postValues, launcherSchema)
584+
}
414585

415586
jwtClaims := GenerateJwtClaims()
416587
for key, v := range jwtClaims {
@@ -448,6 +619,38 @@ func GenerateTokenFromPost(postValues url.Values) (string, string) {
448619

449620
// GetRequiredMetadata Gets the required metadata from a schema
450621
func GetRequiredMetadata(launcherSchema surveys.LauncherSchema) ([]Metadata, string) {
622+
schema, error := getSchema(launcherSchema)
623+
if error != "" {
624+
return nil, fmt.Sprintf("getSchema failed err: %v", error)
625+
}
626+
627+
defaults := GetDefaultValues()
628+
629+
for i, value := range schema.Metadata {
630+
schema.Metadata[i].Default = defaults[value.Name]
631+
632+
if value.Validator == "boolean" {
633+
schema.Metadata[i].Default = "false"
634+
}
635+
}
636+
637+
claims := make([]string, 0)
638+
for _, v := range schema.Metadata {
639+
claims = append(claims, v.Name)
640+
}
641+
642+
mandatoryClaims := getMandatatoryClaims(schema.SurveyType, defaults)
643+
644+
missingClaims := getMissingMandatoryClaims(claims, mandatoryClaims)
645+
646+
for _, v := range missingClaims {
647+
schema.Metadata = append(schema.Metadata, v)
648+
}
649+
650+
return schema.Metadata, ""
651+
}
652+
653+
func getSchema(launcherSchema surveys.LauncherSchema) (QuestionnaireSchema, string) {
451654
var url string
452655

453656
if launcherSchema.URL != "" {
@@ -461,50 +664,80 @@ func GetRequiredMetadata(launcherSchema surveys.LauncherSchema) ([]Metadata, str
461664

462665
log.Println("Loading metadata from schema:", url)
463666

667+
var schema QuestionnaireSchema
464668
resp, err := clients.GetHTTPClient().Get(url)
465669
if err != nil {
466670
log.Println("Failed to load schema from:", url)
467-
return nil, fmt.Sprintf("Failed to load Schema from %s", url)
671+
return schema, fmt.Sprintf("Failed to load Schema from %s", url)
468672
}
469673

470674
if resp.StatusCode != 200 {
471675
log.Print("Invalid response code for schema from: ", url)
472-
return nil, fmt.Sprintf("Failed to load Schema from %s", url)
676+
return schema, fmt.Sprintf("Failed to load Schema from %s", url)
473677
}
474678

475679
responseBody, err := ioutil.ReadAll(resp.Body)
476680
resp.Body.Close()
477681
if err != nil {
478682
log.Print(err)
479-
return nil, fmt.Sprintf("Failed to load Schema from %s", url)
683+
return schema, fmt.Sprintf("Failed to load Schema from %s", url)
480684
}
481685

482-
var schema QuestionnaireSchema
483686
if err := json.Unmarshal(responseBody, &schema); err != nil {
484687
log.Print(err)
485-
return nil, fmt.Sprintf("Failed to unmarshal Schema from %s", url)
688+
return schema, fmt.Sprintf("Failed to unmarshal Schema from %s", url)
486689
}
487690

488-
defaults := GetDefaultValues()
691+
return schema, ""
692+
}
489693

490-
for i, value := range schema.Metadata {
491-
schema.Metadata[i].Default = defaults[value.Name]
694+
func getMandatatoryClaims(surveyType string, defaults map[string]string) []Metadata {
695+
claims := make([]Metadata, 0)
696+
if surveyType == "health" || surveyType == "social" {
697+
claims = []Metadata{
698+
{"qid", "false", defaults["qid"]},
699+
}
492700

493-
if value.Validator == "boolean" {
494-
schema.Metadata[i].Default = "false"
701+
} else {
702+
claims = []Metadata{
703+
{"ru_ref", "false", defaults["ru_ref"]},
704+
{"period_id", "false", defaults["period_id"]},
705+
{"user_id", "false", defaults["user_id"]},
495706
}
496707
}
497708

498-
return schema.Metadata, ""
709+
return claims
710+
}
711+
712+
func getMissingMandatoryClaims(claims []string, mandatoryClaims []Metadata) []Metadata {
713+
missingClaims := make([]Metadata, 0)
714+
for _, v := range mandatoryClaims {
715+
if !(stringInSlice(v.Name, claims)) {
716+
missingClaims = append(missingClaims, v)
717+
}
718+
}
719+
720+
return missingClaims
721+
}
722+
723+
func stringInSlice(a string, list []string) bool {
724+
for _, b := range list {
725+
if b == a {
726+
return true
727+
}
728+
}
729+
return false
499730
}
500731

501732
// GetDefaultValues Returns a map of default values for metadata keys
502733
func GetDefaultValues() map[string]string {
503-
504734
defaults := make(map[string]string)
505-
506735
collectionExerciseSid, _ := uuid.NewV4()
507736

737+
defaults["collection_exercise_sid"] = collectionExerciseSid.String()
738+
defaults["qid"] = fmt.Sprintf("%016d", rand.Int63n(1e16))
739+
defaults["version"] = "v2"
740+
defaults["case_type"] = "B"
508741
defaults["user_id"] = "UNKNOWN"
509742
defaults["period_id"] = "201605"
510743
defaults["period_str"] = "May 2017"

0 commit comments

Comments
 (0)