aws / aws-lambda-go

Libraries, samples and tools to help Go developers develop AWS Lambda functions.
Apache License 2.0
3.58k stars 548 forks source link

Deserialisation of array values in Cognito events custom UserAttributes not working correctly #532

Closed DanielHoffmann closed 7 months ago

DanielHoffmann commented 7 months ago

Is your feature request related to a problem? Please describe.

It seems that the Cognito Events can not properly handle UserAttributes values that are arrays, the serialisation doesn't seem to be working correctly and I only get the first value from the list as a plain string.

According to Microsoft Azure AD documentation:

https://theitbros.com/create-custom-user-attribute-in-azure-ad/

Custom UserAttributes can be a list of strings

For example, in my Identity provider I have a mapping of "custom:ad-groups" (which is a list of strings) to get groups from Azure AD

Screenshot 2023-11-15 at 16 38 07

however the UserAttributes["custom:ad-groups"] field only ever has a single value, no matter how many different values I assign in Azure AD for a user. For example this is the event I am getting for my user (sensitive values replaced with "a"s):

         events.CognitoEventUserPoolsPreAuthentication{
        CognitoEventUserPoolsHeader: events.CognitoEventUserPoolsHeader{
            Version:       "1",
            TriggerSource: "PreAuthentication_Authentication",
            Region:        "eu-west-1",
            UserPoolID:    "eu-west-1_aaaaaaaaa",
            CallerContext: events.CognitoEventUserPoolsCallerContext{
                AWSSDKVersion: "aws-sdk-unknown-unknown",
                ClientID:      "aaaaaaaaaaaaaaaaaaaaaa",
            },
            UserName: "Northvolt_daniel.hoffmann@northvolt.com",
        },
        Request: events.CognitoEventUserPoolsPreAuthenticationRequest{
            UserAttributes: map[string]string{
                "cognito:user_status": "EXTERNAL_PROVIDER",
                "custom:ad-groups":    "6e52aaaa-aaaaaa-aaaaa-aaaaaaa",
                "email":               "aaaaaaa@aaaaa.com",
                "email_verified":      "false",
                "family_name":         "aaaaa",
                "given_name":          "aaaaa",
                "identities":          "[{\"userId\":\"aaaaaaa@aaaaa.com\",\"providerName\":\"Aaaaaa\",\"providerType\":\"SAML\",\"issuer\":\"https://sts.windows.net/aaaaaaaaaaaaaaaaaaaaaa/\",\"primary\":true,\"dateCreated\":1697630727679}]", "name": "aaaaaaa@aaaaa.com", "sub": "aaaaaaaaaaaaaaaaaaaaaa",
            },
            ValidationData: map[string]string{},
        },
        Response: events.CognitoEventUserPoolsPreAuthenticationResponse{},
    }

as you can see event.Request.UserAttributes["custom:ad-groups"] is a single value instead of a list of values

Describe the solution you'd like

It seems there is no standard way of encoding arrays for custom UserAttributes, so if the value is not a plain string it seems the serialisation should be handled like UserAttributes["identities"] (a string with JSON inside), so like this:

 "custom:ad-groups":    "[\"6e52aaaa-aaaaaa-aaaaa-aaaaaaa\", \"81edaaaa-aaaaaa-aaaaa-aaaaaaa\"]",

Additional context

I replaced my golang lambda with a javascript lambda and in Javascript I get a proper array inside userAttributes["custom:ad-groups"]:

         "userAttributes": {
            "custom:ad-groups": ["6e52aaaa-aaaaaa-aaaaa-aaaaaaa", "81edaaaa-aaaaaa-aaaaa-aaaaaaa"],
             ...
        }

so it seems there is nothing wrong in the Azure AD side, only on the golang deserialisation of the values.

DanielHoffmann commented 7 months ago

Turns out the problem was that the user I was testing with had only one AD Groups when I first logged in, then added more groups after the login.

So if the user has only one value the data gets serialized as this:

"custom:whatever": "value"

if the user has multiple values the data gets serialised as this:

"custom:whatever": "[value1, value2]"

note no quotes around the values inside the array which is a bit weird I suppose