From 2d6ac5672f64ae18eed5288c0154fbf4bc85c745 Mon Sep 17 00:00:00 2001 From: Rishu Harpavat Date: Thu, 22 Feb 2024 16:57:11 -0800 Subject: [PATCH] Add PoP token support for ROPC flow (#412) * Add PoP token support for ROPC flow Add VCR tests for ROPC flow Fix formatting issues Add VCR tests for ROPC flow * Vendor msal release v1.2.2 * Redact username + tenantID, fix failing test * Split msal into confidential+public, add tests * Fix typo * Add tests for getPublicClient * Make tokenWithOptions private to token package --------- Co-authored-by: rharpavat --- go.mod | 2 +- go.sum | 4 +- .../pop/{msal.go => msal_confidential.go} | 50 --- ...msal_test.go => msal_confidential_test.go} | 0 pkg/internal/pop/msal_public.go | 115 ++++++ pkg/internal/pop/msal_public_test.go | 217 +++++++++++ ...nByUsernamePasswordFromBadPasswordVCR.yaml | 247 +++++++++++++ .../AcquirePoPTokenByUsernamePasswordVCR.yaml | 336 ++++++++++++++++++ pkg/internal/testutils/govcrutils.go | 25 +- pkg/internal/testutils/testutils.go | 21 +- pkg/internal/testutils/testutils_test.go | 35 ++ pkg/internal/token/provider.go | 2 +- pkg/internal/token/ropc.go | 62 +++- pkg/internal/token/ropc_test.go | 235 ++++++++++++ .../ROPCPoPTokenFromBadPasswordVCR.yaml | 247 +++++++++++++ .../ROPCPoPTokenFromUsernamePasswordVCR.yaml | 336 ++++++++++++++++++ 16 files changed, 1876 insertions(+), 58 deletions(-) rename pkg/internal/pop/{msal.go => msal_confidential.go} (57%) rename pkg/internal/pop/{msal_test.go => msal_confidential_test.go} (100%) create mode 100644 pkg/internal/pop/msal_public.go create mode 100644 pkg/internal/pop/msal_public_test.go create mode 100644 pkg/internal/pop/testdata/AcquirePoPTokenByUsernamePasswordFromBadPasswordVCR.yaml create mode 100644 pkg/internal/pop/testdata/AcquirePoPTokenByUsernamePasswordVCR.yaml create mode 100644 pkg/internal/token/ropc_test.go create mode 100644 pkg/internal/token/testdata/ROPCPoPTokenFromBadPasswordVCR.yaml create mode 100644 pkg/internal/token/testdata/ROPCPoPTokenFromUsernamePasswordVCR.yaml diff --git a/go.mod b/go.mod index 82083c37..d3e62d8e 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 github.com/Azure/go-autorest/autorest v0.11.29 github.com/Azure/go-autorest/autorest/adal v0.9.23 - github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 + github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 github.com/golang-jwt/jwt/v4 v4.5.0 github.com/golang-jwt/jwt/v5 v5.2.0 github.com/google/go-cmp v0.6.0 diff --git a/go.sum b/go.sum index 7aceb2aa..e05e7f91 100644 --- a/go.sum +++ b/go.sum @@ -21,8 +21,8 @@ github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+Z github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= -github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 h1:DzHpqpoJVaCgOUdVHxE8QB52S6NiVdDQvGlny1qvPqA= -github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= diff --git a/pkg/internal/pop/msal.go b/pkg/internal/pop/msal_confidential.go similarity index 57% rename from pkg/internal/pop/msal.go rename to pkg/internal/pop/msal_confidential.go index 706ea7a6..d31f879b 100644 --- a/pkg/internal/pop/msal.go +++ b/pkg/internal/pop/msal_confidential.go @@ -7,58 +7,8 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential" - "github.com/AzureAD/microsoft-authentication-library-for-go/apps/public" ) -// AcquirePoPTokenInteractive acquires a PoP token using MSAL's interactive login flow. -// Requires user to authenticate via browser -func AcquirePoPTokenInteractive( - context context.Context, - popClaims map[string]string, - scopes []string, - authority, - clientID string, - options *azcore.ClientOptions, -) (string, int64, error) { - var client public.Client - var err error - if options != nil && options.Transport != nil { - client, err = public.New( - clientID, - public.WithAuthority(authority), - public.WithHTTPClient(options.Transport.(*http.Client)), - ) - } else { - client, err = public.New( - clientID, - public.WithAuthority(authority), - ) - } - if err != nil { - return "", -1, fmt.Errorf("unable to create public client: %w", err) - } - - popKey, err := GetSwPoPKey() - if err != nil { - return "", -1, err - } - result, err := client.AcquireTokenInteractive( - context, - scopes, - public.WithAuthenticationScheme( - &PoPAuthenticationScheme{ - Host: popClaims["u"], - PoPKey: popKey, - }, - ), - ) - if err != nil { - return "", -1, fmt.Errorf("failed to create PoP token with interactive flow: %w", err) - } - - return result.AccessToken, result.ExpiresOn.Unix(), nil -} - // AcquirePoPTokenConfidential acquires a PoP token using MSAL's confidential login flow. // This flow does not require user interaction as the credentials for the request have // already been provided diff --git a/pkg/internal/pop/msal_test.go b/pkg/internal/pop/msal_confidential_test.go similarity index 100% rename from pkg/internal/pop/msal_test.go rename to pkg/internal/pop/msal_confidential_test.go diff --git a/pkg/internal/pop/msal_public.go b/pkg/internal/pop/msal_public.go new file mode 100644 index 00000000..5f9c8366 --- /dev/null +++ b/pkg/internal/pop/msal_public.go @@ -0,0 +1,115 @@ +package pop + +import ( + "context" + "fmt" + "net/http" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore" + "github.com/AzureAD/microsoft-authentication-library-for-go/apps/public" +) + +// AcquirePoPTokenInteractive acquires a PoP token using MSAL's interactive login flow. +// Requires user to authenticate via browser +func AcquirePoPTokenInteractive( + context context.Context, + popClaims map[string]string, + scopes []string, + authority, + clientID string, + options *azcore.ClientOptions, +) (string, int64, error) { + var client *public.Client + var err error + client, err = getPublicClient(authority, clientID, options) + if err != nil { + return "", -1, err + } + + popKey, err := GetSwPoPKey() + if err != nil { + return "", -1, err + } + result, err := client.AcquireTokenInteractive( + context, + scopes, + public.WithAuthenticationScheme( + &PoPAuthenticationScheme{ + Host: popClaims["u"], + PoPKey: popKey, + }, + ), + ) + if err != nil { + return "", -1, fmt.Errorf("failed to create PoP token with interactive flow: %w", err) + } + + return result.AccessToken, result.ExpiresOn.Unix(), nil +} + +// AcquirePoPTokenByUsernamePassword acquires a PoP token using MSAL's username/password login flow +// This flow does not require user interaction as credentials have already been provided +func AcquirePoPTokenByUsernamePassword( + context context.Context, + popClaims map[string]string, + scopes []string, + authority, + clientID, + username, + password string, + options *azcore.ClientOptions, +) (string, int64, error) { + client, err := getPublicClient(authority, clientID, options) + if err != nil { + return "", -1, err + } + + popKey, err := GetSwPoPKey() + if err != nil { + return "", -1, err + } + result, err := client.AcquireTokenByUsernamePassword( + context, + scopes, + username, + password, + public.WithAuthenticationScheme( + &PoPAuthenticationScheme{ + Host: popClaims["u"], + PoPKey: popKey, + }, + ), + ) + if err != nil { + return "", -1, fmt.Errorf("failed to create PoP token with username/password flow: %w", err) + } + + return result.AccessToken, result.ExpiresOn.Unix(), nil +} + +// getPublicClient returns an instance of the msal `public` client based on the provided options +func getPublicClient( + authority, + clientID string, + options *azcore.ClientOptions, +) (*public.Client, error) { + var client public.Client + var err error + if options != nil && options.Transport != nil { + client, err = public.New( + clientID, + public.WithAuthority(authority), + public.WithHTTPClient(options.Transport.(*http.Client)), + ) + } else { + client, err = public.New( + clientID, + public.WithAuthority(authority), + ) + } + if err != nil { + return nil, fmt.Errorf("unable to create public client: %w", err) + } + + return &client, nil +} diff --git a/pkg/internal/pop/msal_public_test.go b/pkg/internal/pop/msal_public_test.go new file mode 100644 index 00000000..3524ba95 --- /dev/null +++ b/pkg/internal/pop/msal_public_test.go @@ -0,0 +1,217 @@ +package pop + +import ( + "context" + "fmt" + "net/http" + "net/url" + "os" + "testing" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud" + "github.com/Azure/go-autorest/autorest/adal" + "github.com/Azure/kubelogin/pkg/internal/testutils" + "github.com/AzureAD/microsoft-authentication-library-for-go/apps/public" + "github.com/golang-jwt/jwt/v4" + "github.com/google/uuid" + "gopkg.in/dnaeon/go-vcr.v3/recorder" +) + +type resourceOwnerTokenVars struct { + clientID string + username string + password string + resourceID string + tenantID string + popClaims map[string]string + oAuthConfig adal.OAuthConfig +} + +func TestAcquirePoPTokenByUsernamePassword(t *testing.T) { + pEnv := &resourceOwnerTokenVars{ + clientID: os.Getenv(testutils.ClientID), + username: os.Getenv(testutils.Username), + password: os.Getenv(testutils.Password), + resourceID: os.Getenv(testutils.ResourceID), + tenantID: os.Getenv(testutils.TenantID), + } + // Use defaults if environmental variables are empty + if pEnv.clientID == "" { + pEnv.clientID = testutils.ClientID + } + if pEnv.username == "" { + pEnv.username = testutils.Username + } + if pEnv.password == "" { + pEnv.password = testutils.Password + } + if pEnv.resourceID == "" { + pEnv.resourceID = testutils.ResourceID + } + if pEnv.tenantID == "" { + pEnv.tenantID = "00000000-0000-0000-0000-000000000000" + } + + ctx := context.Background() + scopes := []string{pEnv.resourceID + "/.default"} + authority := "https://login.microsoftonline.com/" + pEnv.tenantID + authorityEndpoint, err := url.Parse(authority) + if err != nil { + t.Errorf("error encountered when parsing active directory endpoint: %s", err) + } + var expectedToken string + var token string + expectedTokenType := "pop" + testCase := []struct { + cassetteName string + p *resourceOwnerTokenVars + expectedError error + }{ + { + // Test using bad password + cassetteName: "AcquirePoPTokenByUsernamePasswordFromBadPasswordVCR", + p: &resourceOwnerTokenVars{ + clientID: pEnv.clientID, + username: pEnv.username, + password: testutils.BadSecret, + resourceID: pEnv.resourceID, + tenantID: pEnv.tenantID, + popClaims: map[string]string{"u": "testhost"}, + oAuthConfig: adal.OAuthConfig{ + AuthorityEndpoint: *authorityEndpoint, + }, + }, + expectedError: fmt.Errorf("failed to create PoP token with username/password flow"), + }, + { + // Test using username/password to get PoP token + cassetteName: "AcquirePoPTokenByUsernamePasswordVCR", + p: &resourceOwnerTokenVars{ + clientID: pEnv.clientID, + username: pEnv.username, + password: pEnv.password, + resourceID: pEnv.resourceID, + tenantID: pEnv.tenantID, + popClaims: map[string]string{"u": "testhost"}, + oAuthConfig: adal.OAuthConfig{ + AuthorityEndpoint: *authorityEndpoint, + }, + }, + expectedError: nil, + }, + } + + for _, tc := range testCase { + t.Run(tc.cassetteName, func(t *testing.T) { + if tc.expectedError == nil { + expectedToken = uuid.New().String() + } + vcrRecorder, httpClient := testutils.GetVCRHttpClient(fmt.Sprintf("testdata/%s", tc.cassetteName), expectedToken) + + clientOpts := azcore.ClientOptions{ + Cloud: cloud.AzurePublic, + Transport: httpClient, + } + + token, _, err = AcquirePoPTokenByUsernamePassword( + ctx, + tc.p.popClaims, + scopes, + authority, + tc.p.clientID, + tc.p.username, + tc.p.password, + &clientOpts, + ) + defer vcrRecorder.Stop() + if tc.expectedError != nil { + if !testutils.ErrorContains(err, tc.expectedError.Error()) { + t.Errorf("expected error %s, but got %s", tc.expectedError.Error(), err) + } + } else if err != nil { + t.Errorf("expected no error, but got: %s", err) + } else { + if token == "" { + t.Error("expected valid token, but received empty token.") + } + claims := jwt.MapClaims{} + parsed, _ := jwt.ParseWithClaims(token, &claims, nil) + if vcrRecorder.Mode() == recorder.ModeReplayOnly { + if claims["at"] != expectedToken { + t.Errorf("unexpected token returned (expected %s, but got %s)", expectedToken, claims["at"]) + } + if parsed.Header["typ"] != expectedTokenType { + t.Errorf("unexpected token returned (expected %s, but got %s)", expectedTokenType, parsed.Header["typ"]) + } + } + } + }) + } +} + +func TestGetPublicClient(t *testing.T) { + httpClient := &http.Client{} + authority := "https://login.microsoftonline.com/" + testutils.TenantID + + testCase := []struct { + testName string + authority string + options *azcore.ClientOptions + expectedError error + }{ + { + // Test using custom HTTP transport + testName: "TestGetPublicClientWithCustomTransport", + authority: authority, + options: &azcore.ClientOptions{ + Cloud: cloud.AzurePublic, + Transport: httpClient, + }, + expectedError: nil, + }, + { + // Test using default HTTP transport + testName: "TestGetPublicClientWithDefaultTransport", + authority: authority, + options: &azcore.ClientOptions{ + Cloud: cloud.AzurePublic, + }, + expectedError: nil, + }, + { + // Test using incorrectly formatted authority + testName: "TestGetPublicClientWithBadAuthority", + authority: "login.microsoft.com", + options: &azcore.ClientOptions{ + Cloud: cloud.AzurePublic, + }, + expectedError: fmt.Errorf("unable to create public client"), + }, + } + + var client *public.Client + var err error + + for _, tc := range testCase { + t.Run(tc.testName, func(t *testing.T) { + client, err = getPublicClient( + tc.authority, + testutils.ClientID, + tc.options, + ) + + if tc.expectedError != nil { + if !testutils.ErrorContains(err, tc.expectedError.Error()) { + t.Errorf("expected error %s, but got %s", tc.expectedError.Error(), err) + } + } else if err != nil { + t.Errorf("expected no error, but got: %s", err) + } else { + if client == nil { + t.Errorf("expected a client but got nil") + } + } + }) + } +} diff --git a/pkg/internal/pop/testdata/AcquirePoPTokenByUsernamePasswordFromBadPasswordVCR.yaml b/pkg/internal/pop/testdata/AcquirePoPTokenByUsernamePasswordFromBadPasswordVCR.yaml new file mode 100644 index 00000000..70ba7558 --- /dev/null +++ b/pkg/internal/pop/testdata/AcquirePoPTokenByUsernamePasswordFromBadPasswordVCR.yaml @@ -0,0 +1,247 @@ +--- +version: 2 +interactions: + - id: 0 + request: + proto: "" + proto_major: 0 + proto_minor: 0 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: "" + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Accept-Encoding: + - gzip + Client-Request-Id: + - 23f1fa48-ea1f-4138-be73-75da7aaa0c7b + Return-Client-Request-Id: + - "false" + X-Client-Cpu: + - amd64 + X-Client-Os: + - linux + X-Client-Sku: + - MSAL.Go + X-Client-Ver: + - 1.2.0 + url: https://login.microsoftonline.com/AZURE_TENANT_ID/v2.0/.well-known/openid-configuration + method: GET + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + transfer_encoding: [] + trailer: {} + content_length: 1753 + uncompressed: false + body: '{"token_endpoint":"https://login.microsoftonline.com/AZURE_TENANT_ID/oauth2/v2.0/token","token_endpoint_auth_methods_supported":["client_secret_post","private_key_jwt","client_secret_basic"],"jwks_uri":"https://login.microsoftonline.com/AZURE_TENANT_ID/discovery/v2.0/keys","response_modes_supported":["query","fragment","form_post"],"subject_types_supported":["pairwise"],"id_token_signing_alg_values_supported":["RS256"],"response_types_supported":["code","id_token","code id_token","id_token token"],"scopes_supported":["openid","profile","email","offline_access"],"issuer":"https://login.microsoftonline.com/AZURE_TENANT_ID/v2.0","request_uri_parameter_supported":false,"userinfo_endpoint":"https://graph.microsoft.com/oidc/userinfo","authorization_endpoint":"https://login.microsoftonline.com/AZURE_TENANT_ID/oauth2/v2.0/authorize","device_authorization_endpoint":"https://login.microsoftonline.com/AZURE_TENANT_ID/oauth2/v2.0/devicecode","http_logout_supported":true,"frontchannel_logout_supported":true,"end_session_endpoint":"https://login.microsoftonline.com/AZURE_TENANT_ID/oauth2/v2.0/logout","claims_supported":["sub","iss","cloud_instance_name","cloud_instance_host_name","cloud_graph_host_name","msgraph_host","aud","exp","iat","auth_time","acr","nonce","preferred_username","name","tid","ver","at_hash","c_hash","email"],"kerberos_endpoint":"https://login.microsoftonline.com/AZURE_TENANT_ID/kerberos","tenant_region_scope":"WW","cloud_instance_name":"microsoftonline.com","cloud_graph_host_name":"graph.windows.net","msgraph_host":"graph.microsoft.com","rbac_url":"https://pas.windows.net"}' + headers: + Access-Control-Allow-Methods: + - GET, OPTIONS + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=86400, private + Client-Request-Id: + - 23f1fa48-ea1f-4138-be73-75da7aaa0c7b + Content-Length: + - "1753" + Content-Type: + - application/json; charset=utf-8 + Date: + - Wed, 21 Feb 2024 21:14:22 GMT + P3p: + - CP="DSP CUR OTPi IND OTRi ONL FIN" + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + X-Content-Type-Options: + - nosniff + X-Ms-Ests-Server: + - 2.1.17396.6 - NCUS ProdSlices + X-Xss-Protection: + - "0" + status: 200 OK + code: 200 + duration: 78.559437ms + - id: 1 + request: + proto: "" + proto_major: 0 + proto_minor: 0 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: "" + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Accept-Encoding: + - gzip + Client-Request-Id: + - 3f8be16e-19b1-4199-a330-deb218ca2f7b + Return-Client-Request-Id: + - "false" + X-Client-Cpu: + - amd64 + X-Client-Os: + - linux + X-Client-Sku: + - MSAL.Go + X-Client-Ver: + - 1.2.0 + client-request-id: + - 8cab3f9c-f9d3-4a46-bbf6-08ac1eb5d1d6 + url: https://login.microsoftonline.com/common/UserRealm/USERNAME?api-version=1.0 + method: GET + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + transfer_encoding: [] + trailer: {} + content_length: 384 + uncompressed: false + body: '{"ver":"1.0","account_type":"Federated","domain_name":"microsoft.com","federation_protocol":"WSTrust","federation_metadata_url":"https://msft.sts.microsoft.com/adfs/services/trust/mex","federation_active_auth_url":"https://msft.sts.microsoft.com/adfs/services/trust/2005/usernamemixed","cloud_instance_name":"microsoftonline.com","cloud_audience_urn":"urn:federation:MicrosoftOnline"}' + headers: + Cache-Control: + - no-store, no-cache + Content-Disposition: + - inline; filename=userrealm.json + Content-Length: + - "384" + Content-Type: + - application/json; charset=utf-8 + Date: + - Wed, 21 Feb 2024 21:14:22 GMT + Expires: + - "-1" + P3p: + - CP="DSP CUR OTPi IND OTRi ONL FIN" + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + X-Content-Type-Options: + - nosniff + X-Ms-Ests-Server: + - 2.1.17396.6 - WUS3 ProdSlices + X-Xss-Protection: + - "0" + status: 200 OK + code: 200 + duration: 108.043413ms + - id: 2 + request: + proto: "" + proto_major: 0 + proto_minor: 0 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: "" + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Accept-Encoding: + - gzip + Client-Request-Id: + - df5fd660-b2c5-4f80-832c-8f5e989d84b4 + Content-Type: + - application/xml; charset=utf-8 + Return-Client-Request-Id: + - "false" + X-Client-Cpu: + - amd64 + X-Client-Os: + - linux + X-Client-Sku: + - MSAL.Go + X-Client-Ver: + - 1.2.0 + url: https://msft.sts.microsoft.com/adfs/services/trust/mex + method: GET + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + transfer_encoding: [] + trailer: {} + content_length: 14784 + uncompressed: false + body: https://msft.sts.microsoft.com/adfs/services/trust/2005/certificatemixedhttps://certauth.msft.sts.microsoft.com/adfs/services/trust/2005/certificatetransporthttps://msft.sts.microsoft.com/adfs/services/trust/2005/usernamemixedhttps://msft.sts.microsoft.com/adfs/services/trust/13/certificatemixedhttps://msft.sts.microsoft.com/adfs/services/trust/13/usernamemixed + headers: + Content-Length: + - "14784" + Content-Type: + - text/xml; charset=UTF-8 + Date: + - Wed, 21 Feb 2024 21:14:22 GMT + Server: + - Microsoft-HTTPAPI/2.0 Microsoft-HTTPAPI/2.0 + status: 200 OK + code: 200 + duration: 905.127372ms + - id: 3 + request: + proto: "" + proto_major: 0 + proto_minor: 0 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: "" + remote_addr: "" + request_uri: "" + body: http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issueurn:uuid:1d5fcd63-9609-49ba-a1ed-bd260dfaf6e7http://www.w3.org/2005/08/addressing/anonymoushttps://msft.sts.microsoft.com/adfs/services/trust/13/usernamemixed2024-02-21T21:14:24.560Z2024-02-21T21:24:24.560ZUSERNAMEBad_Secreturn:federation:MicrosoftOnlinehttp://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearerhttp://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue + form: {} + headers: + Accept-Encoding: + - gzip + Client-Request-Id: + - 024cc5e1-6771-462d-842b-614f867b7562 + Content-Type: + - application/soap+xml; charset=utf-8 + Return-Client-Request-Id: + - "false" + Soapaction: + - http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue + X-Client-Cpu: + - amd64 + X-Client-Os: + - linux + X-Client-Sku: + - MSAL.Go + X-Client-Ver: + - 1.2.0 + url: https://msft.sts.microsoft.com/adfs/services/trust/13/usernamemixed + method: POST + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + transfer_encoding: [] + trailer: {} + content_length: 953 + uncompressed: false + body: 'http://www.w3.org/2005/08/addressing/soap/fault2024-02-21T21:14:25.473Z2024-02-21T21:19:25.473Zs:Sendera:FailedAuthenticationID3242: The security token could not be authenticated or authorized.' + headers: + Content-Length: + - "953" + Content-Type: + - application/soap+xml; charset=utf-8 + Date: + - Wed, 21 Feb 2024 21:14:25 GMT + Server: + - Microsoft-HTTPAPI/2.0 Microsoft-HTTPAPI/2.0 + status: 500 Internal Server Error + code: 500 + duration: 1.090492286s diff --git a/pkg/internal/pop/testdata/AcquirePoPTokenByUsernamePasswordVCR.yaml b/pkg/internal/pop/testdata/AcquirePoPTokenByUsernamePasswordVCR.yaml new file mode 100644 index 00000000..b4e14d9f --- /dev/null +++ b/pkg/internal/pop/testdata/AcquirePoPTokenByUsernamePasswordVCR.yaml @@ -0,0 +1,336 @@ +--- +version: 2 +interactions: + - id: 0 + request: + proto: "" + proto_major: 0 + proto_minor: 0 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: "" + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Accept-Encoding: + - gzip + Client-Request-Id: + - 9daec4f1-ed1b-4b64-ba36-d3d34be1a2ac + Return-Client-Request-Id: + - "false" + X-Client-Cpu: + - amd64 + X-Client-Os: + - linux + X-Client-Sku: + - MSAL.Go + X-Client-Ver: + - 1.2.0 + url: https://login.microsoftonline.com/AZURE_TENANT_ID/v2.0/.well-known/openid-configuration + method: GET + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + transfer_encoding: [] + trailer: {} + content_length: 1753 + uncompressed: false + body: '{"token_endpoint":"https://login.microsoftonline.com/AZURE_TENANT_ID/oauth2/v2.0/token","token_endpoint_auth_methods_supported":["client_secret_post","private_key_jwt","client_secret_basic"],"jwks_uri":"https://login.microsoftonline.com/AZURE_TENANT_ID/discovery/v2.0/keys","response_modes_supported":["query","fragment","form_post"],"subject_types_supported":["pairwise"],"id_token_signing_alg_values_supported":["RS256"],"response_types_supported":["code","id_token","code id_token","id_token token"],"scopes_supported":["openid","profile","email","offline_access"],"issuer":"https://login.microsoftonline.com/AZURE_TENANT_ID/v2.0","request_uri_parameter_supported":false,"userinfo_endpoint":"https://graph.microsoft.com/oidc/userinfo","authorization_endpoint":"https://login.microsoftonline.com/AZURE_TENANT_ID/oauth2/v2.0/authorize","device_authorization_endpoint":"https://login.microsoftonline.com/AZURE_TENANT_ID/oauth2/v2.0/devicecode","http_logout_supported":true,"frontchannel_logout_supported":true,"end_session_endpoint":"https://login.microsoftonline.com/AZURE_TENANT_ID/oauth2/v2.0/logout","claims_supported":["sub","iss","cloud_instance_name","cloud_instance_host_name","cloud_graph_host_name","msgraph_host","aud","exp","iat","auth_time","acr","nonce","preferred_username","name","tid","ver","at_hash","c_hash","email"],"kerberos_endpoint":"https://login.microsoftonline.com/AZURE_TENANT_ID/kerberos","tenant_region_scope":"WW","cloud_instance_name":"microsoftonline.com","cloud_graph_host_name":"graph.windows.net","msgraph_host":"graph.microsoft.com","rbac_url":"https://pas.windows.net"}' + headers: + Access-Control-Allow-Methods: + - GET, OPTIONS + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=86400, private + Client-Request-Id: + - 9daec4f1-ed1b-4b64-ba36-d3d34be1a2ac + Content-Length: + - "1753" + Content-Type: + - application/json; charset=utf-8 + Date: + - Wed, 21 Feb 2024 21:14:26 GMT + P3p: + - CP="DSP CUR OTPi IND OTRi ONL FIN" + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + X-Content-Type-Options: + - nosniff + X-Ms-Ests-Server: + - 2.1.17396.6 - WUS3 ProdSlices + X-Xss-Protection: + - "0" + status: 200 OK + code: 200 + duration: 64.332046ms + - id: 1 + request: + proto: "" + proto_major: 0 + proto_minor: 0 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: "" + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Accept-Encoding: + - gzip + Client-Request-Id: + - 42056c1d-e293-4aa2-bb17-97776c6917de + Return-Client-Request-Id: + - "false" + X-Client-Cpu: + - amd64 + X-Client-Os: + - linux + X-Client-Sku: + - MSAL.Go + X-Client-Ver: + - 1.2.0 + client-request-id: + - e4609b88-b598-4382-b13a-51bf51f8b458 + url: https://login.microsoftonline.com/common/UserRealm/USERNAME?api-version=1.0 + method: GET + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + transfer_encoding: [] + trailer: {} + content_length: 384 + uncompressed: false + body: '{"ver":"1.0","account_type":"Federated","domain_name":"microsoft.com","federation_protocol":"WSTrust","federation_metadata_url":"https://msft.sts.microsoft.com/adfs/services/trust/mex","federation_active_auth_url":"https://msft.sts.microsoft.com/adfs/services/trust/2005/usernamemixed","cloud_instance_name":"microsoftonline.com","cloud_audience_urn":"urn:federation:MicrosoftOnline"}' + headers: + Cache-Control: + - no-store, no-cache + Content-Disposition: + - inline; filename=userrealm.json + Content-Length: + - "384" + Content-Type: + - application/json; charset=utf-8 + Date: + - Wed, 21 Feb 2024 21:14:27 GMT + Expires: + - "-1" + P3p: + - CP="DSP CUR OTPi IND OTRi ONL FIN" + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + X-Content-Type-Options: + - nosniff + X-Ms-Ests-Server: + - 2.1.17396.6 - WUS3 ProdSlices + X-Xss-Protection: + - "0" + status: 200 OK + code: 200 + duration: 70.175341ms + - id: 2 + request: + proto: "" + proto_major: 0 + proto_minor: 0 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: "" + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Accept-Encoding: + - gzip + Client-Request-Id: + - fbe23136-87f3-4aa2-98f6-751774fbfa3c + Content-Type: + - application/xml; charset=utf-8 + Return-Client-Request-Id: + - "false" + X-Client-Cpu: + - amd64 + X-Client-Os: + - linux + X-Client-Sku: + - MSAL.Go + X-Client-Ver: + - 1.2.0 + url: https://msft.sts.microsoft.com/adfs/services/trust/mex + method: GET + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + transfer_encoding: [] + trailer: {} + content_length: 14784 + uncompressed: false + body: https://msft.sts.microsoft.com/adfs/services/trust/2005/certificatemixedhttps://certauth.msft.sts.microsoft.com/adfs/services/trust/2005/certificatetransporthttps://msft.sts.microsoft.com/adfs/services/trust/2005/usernamemixedhttps://msft.sts.microsoft.com/adfs/services/trust/13/certificatemixedhttps://msft.sts.microsoft.com/adfs/services/trust/13/usernamemixed + headers: + Content-Length: + - "14784" + Content-Type: + - text/xml; charset=UTF-8 + Date: + - Wed, 21 Feb 2024 21:14:27 GMT + Server: + - Microsoft-HTTPAPI/2.0 Microsoft-HTTPAPI/2.0 + status: 200 OK + code: 200 + duration: 223.877512ms + - id: 3 + request: + proto: "" + proto_major: 0 + proto_minor: 0 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: "" + remote_addr: "" + request_uri: "" + body: http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issueurn:uuid:c3163081-59ba-443d-bfe0-4f3c2e343fa7http://www.w3.org/2005/08/addressing/anonymoushttps://msft.sts.microsoft.com/adfs/services/trust/13/usernamemixed2024-02-21T21:14:27.575Z2024-02-21T21:24:27.575ZUSERNAME[REDACTED]urn:federation:MicrosoftOnlinehttp://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearerhttp://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue + form: {} + headers: + Accept-Encoding: + - gzip + Client-Request-Id: + - b4273c15-60fd-4be1-b538-10de45a3843b + Content-Type: + - application/soap+xml; charset=utf-8 + Return-Client-Request-Id: + - "false" + Soapaction: + - http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue + X-Client-Cpu: + - amd64 + X-Client-Os: + - linux + X-Client-Sku: + - MSAL.Go + X-Client-Ver: + - 1.2.0 + url: https://msft.sts.microsoft.com/adfs/services/trust/13/usernamemixed + method: POST + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + transfer_encoding: [] + trailer: {} + content_length: 9894 + uncompressed: false + body: http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTRC/IssueFinal2024-02-21T21:14:27.770Z2024-02-21T21:19:27.770Z2024-02-21T21:14:27.770Z2024-02-21T22:14:27.770Zurn:federation:MicrosoftOnlineurn:federation:MicrosoftOnline4pGK4tThCkamJqAj33shZA==urn:oasis:names:tc:SAML:1.0:cm:bearerUSERNAME4pGK4tThCkamJqAj33shZA==4pGK4tThCkamJqAj33shZA==4pGK4tThCkamJqAj33shZA==http://schemas.microsoft.com/ws/2008/06/identity/authenticationmethod/password2024-09-21T21:00:03.757Zhttps://sspm.microsoft.comb4273c15-60fd-4be1-b538-10de45a3843b4pGK4tThCkamJqAj33shZA==urn:oasis:names:tc:SAML:1.0:cm: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_cc4cc62c-43fa-4054-95ec-8931c0277f7a_cc4cc62c-43fa-4054-95ec-8931c0277f7aurn:oasis:names:tc:SAML:1.0:assertionhttp://docs.oasis-open.org/ws-sx/ws-trust/200512/Issuehttp://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer + headers: + Content-Length: + - "9894" + Content-Type: + - application/soap+xml; charset=utf-8 + Date: + - Wed, 21 Feb 2024 21:14:27 GMT + Server: + - Microsoft-HTTPAPI/2.0 Microsoft-HTTPAPI/2.0 + status: 200 OK + code: 200 + duration: 382.05008ms + - id: 4 + request: + proto: "" + proto_major: 0 + proto_minor: 0 + content_length: 9902 + transfer_encoding: [] + trailer: {} + host: "" + remote_addr: "" + request_uri: "" + body: assertion=PHNhbWw6QXNzZXJ0aW9uIE1ham9yVmVyc2lvbj0iMSIgTWlub3JWZXJzaW9uPSIxIiBBc3NlcnRpb25JRD0iX2NjNGNjNjJjLTQzZmEtNDA1NC05NWVjLTg5MzFjMDI3N2Y3YSIgSXNzdWVyPSJ1cm46ZmVkZXJhdGlvbjpNU0ZUIiBJc3N1ZUluc3RhbnQ9IjIwMjQtMDItMjFUMjE6MTQ6MjcuNzcwWiIgeG1sbnM6c2FtbD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4wOmFzc2VydGlvbiI%2BPHNhbWw6Q29uZGl0aW9ucyBOb3RCZWZvcmU9IjIwMjQtMDItMjFUMjE6MTQ6MjcuNzcwWiIgTm90T25PckFmdGVyPSIyMDI0LTAyLTIxVDIyOjE0OjI3Ljc3MFoiPjxzYW1sOkF1ZGllbmNlUmVzdHJpY3Rpb25Db25kaXRpb24%2BPHNhbWw6QXVkaWVuY2U%2BdXJuOmZlZGVyYXRpb246TWljcm9zb2Z0T25saW5lPC9zYW1sOkF1ZGllbmNlPjwvc2FtbDpBdWRpZW5jZVJlc3RyaWN0aW9uQ29uZGl0aW9uPjwvc2FtbDpDb25kaXRpb25zPjxzYW1sOkF0dHJpYnV0ZVN0YXRlbWVudD48c2FtbDpTdWJqZWN0PjxzYW1sOk5hbWVJZGVudGlmaWVyIEZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4xOm5hbWVpZC1mb3JtYXQ6dW5zcGVjaWZpZWQiPjRwR0s0dFRoQ2thbUpxQWozM3NoWkE9PTwvc2FtbDpOYW1lSWRlbnRpZmllcj48c2FtbDpTdWJqZWN0Q29uZmlybWF0aW9uPjxzYW1sOkNvbmZpcm1hdGlvbk1ldGhvZD51cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoxLjA6Y206YmVhcmVyPC9zYW1sOkNvbmZpcm1hdGlvbk1ldGhvZD48L3NhbWw6U3ViamVjdENvbmZpcm1hdGlvbj48L3NhbWw6U3ViamVjdD48c2FtbDpBdHRyaWJ1dGUgQXR0cmlidXRlTmFtZT0iVVBOIiBBdHRyaWJ1dGVOYW1lc3BhY2U9Imh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL2NsYWltcyI%2BPHNhbWw6QXR0cmlidXRlVmFsdWU%2Bazhjb25uZWN0c2FAbWljcm9zb2Z0LmNvbTwvc2FtbDpBdHRyaWJ1dGVWYWx1ZT48L3NhbWw6QXR0cmlidXRlPjxzYW1sOkF0dHJpYnV0ZSBBdHRyaWJ1dGVOYW1lPSJvYmplY3RHVUlEIiBBdHRyaWJ1dGVOYW1lc3BhY2U9Imh0dHA6Ly90ZW1wdXJpLmNvbSI%2BPHNhbWw6QXR0cmlidXRlVmFsdWU%2BNHBHSzR0VGhDa2FtSnFBajMzc2haQT09PC9zYW1sOkF0dHJpYnV0ZVZhbHVlPjwvc2FtbDpBdHRyaWJ1dGU%2BPHNhbWw6QXR0cmlidXRlIEF0dHJpYnV0ZU5hbWU9IlBlcnNvbm5lbE51bWJlciIgQXR0cmlidXRlTmFtZXNwYWNlPSJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy9jbGFpbXMiPjxzYW1sOkF0dHJpYnV0ZVZhbHVlPjRwR0s0dFRoQ2thbUpxQWozM3NoWkE9PTwvc2FtbDpBdHRyaWJ1dGVWYWx1ZT48L3NhbWw6QXR0cmlidXRlPjxzYW1sOkF0dHJpYnV0ZSBBdHRyaWJ1dGVOYW1lPSJJbW11dGFibGVJRCIgQXR0cmlidXRlTmFtZXNwYWNlPSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL0xpdmVJRC9GZWRlcmF0aW9uLzIwMDgvMDUiPjxzYW1sOkF0dHJpYnV0ZVZhbHVlPjRwR0s0dFRoQ2thbUpxQWozM3NoWkE9PTwvc2FtbDpBdHRyaWJ1dGVWYWx1ZT48L3NhbWw6QXR0cmlidXRlPjxzYW1sOkF0dHJpYnV0ZSBBdHRyaWJ1dGVOYW1lPSJhdXRobm1ldGhvZHNyZWZlcmVuY2VzIiBBdHRyaWJ1dGVOYW1lc3BhY2U9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vY2xhaW1zIj48c2FtbDpBdHRyaWJ1dGVWYWx1ZT5odHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvYXV0aGVudGljYXRpb25tZXRob2QvcGFzc3dvcmQ8L3NhbWw6QXR0cmlidXRlVmFsdWU%2BPC9zYW1sOkF0dHJpYnV0ZT48c2FtbDpBdHRyaWJ1dGUgQXR0cmlidXRlTmFtZT0icGFzc3dvcmRleHBpcmF0aW9udGltZSIgQXR0cmlidXRlTmFtZXNwYWNlPSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMTIvMDEiPjxzYW1sOkF0dHJpYnV0ZVZhbHVlPjIwMjQtMDktMjFUMjE6MDA6MDMuNzU3Wjwvc2FtbDpBdHRyaWJ1dGVWYWx1ZT48L3NhbWw6QXR0cmlidXRlPjxzYW1sOkF0dHJpYnV0ZSBBdHRyaWJ1dGVOYW1lPSJwYXNzd29yZGNoYW5nZXVybCIgQXR0cmlidXRlTmFtZXNwYWNlPSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMTIvMDEiPjxzYW1sOkF0dHJpYnV0ZVZhbHVlPmh0dHBzOi8vc3NwbS5taWNyb3NvZnQuY29tPC9zYW1sOkF0dHJpYnV0ZVZhbHVlPjwvc2FtbDpBdHRyaWJ1dGU%2BPHNhbWw6QXR0cmlidXRlIEF0dHJpYnV0ZU5hbWU9ImNsaWVudC1yZXF1ZXN0LWlkIiBBdHRyaWJ1dGVOYW1lc3BhY2U9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vMjAxMi8wMS9yZXF1ZXN0Y29udGV4dC9jbGFpbXMiIGE6T3JpZ2luYWxJc3N1ZXI9IkNMSUVOVCBDT05URVhUIiB4bWxuczphPSJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA5LzA5L2lkZW50aXR5L2NsYWltcyI%2BPHNhbWw6QXR0cmlidXRlVmFsdWU%2BYjQyNzNjMTUtNjBmZC00YmUxLWI1MzgtMTBkZTQ1YTM4NDNiPC9zYW1sOkF0dHJpYnV0ZVZhbHVlPjwvc2FtbDpBdHRyaWJ1dGU%2BPC9zYW1sOkF0dHJpYnV0ZVN0YXRlbWVudD48c2FtbDpBdXRoZW50aWNhdGlvblN0YXRlbWVudCBBdXRoZW50aWNhdGlvbk1ldGhvZD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4wOmFtOnBhc3N3b3JkIiBBdXRoZW50aWNhdGlvbkluc3RhbnQ9IjIwMjQtMDItMjFUMjE6MTQ6MjcuNzA3WiI%2BPHNhbWw6U3ViamVjdD48c2FtbDpOYW1lSWRlbnRpZmllciBGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjEuMTpuYW1laWQtZm9ybWF0OnVuc3BlY2lmaWVkIj40cEdLNHRUaENrYW1KcUFqMzNzaFpBPT08L3NhbWw6TmFtZUlkZW50aWZpZXI%2BPHNhbWw6U3ViamVjdENvbmZpcm1hdGlvbj48c2FtbDpDb25maXJtYXRpb25NZXRob2Q%2BdXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4wOmNtOmJlYXJlcjwvc2FtbDpDb25maXJtYXRpb25NZXRob2Q%2BPC9zYW1sOlN1YmplY3RDb25maXJtYXRpb24%2BPC9zYW1sOlN1YmplY3Q%2BPC9zYW1sOkF1dGhlbnRpY2F0aW9uU3RhdGVtZW50PjxkczpTaWduYXR1cmUgeG1sbnM6ZHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiPjxkczpTaWduZWRJbmZvPjxkczpDYW5vbmljYWxpemF0aW9uTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIi8%2BPGRzOlNpZ25hdHVyZU1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZHNpZy1tb3JlI3JzYS1zaGEyNTYiLz48ZHM6UmVmZXJlbmNlIFVSST0iI19jYzRjYzYyYy00M2ZhLTQwNTQtOTVlYy04OTMxYzAyNzdmN2EiPjxkczpUcmFuc2Zvcm1zPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjZW52ZWxvcGVkLXNpZ25hdHVyZSIvPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiLz48L2RzOlRyYW5zZm9ybXM%2BPGRzOkRpZ2VzdE1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jI3NoYTI1NiIvPjxkczpEaWdlc3RWYWx1ZT40ei9zWmFWalQvWmhzR2RYUXdWZVlpaEVTcVYrRlh0cVhrYWN5cE8xNWhZPTwvZHM6RGlnZXN0VmFsdWU%2BPC9kczpSZWZlcmVuY2U%2BPC9kczpTaWduZWRJbmZvPjxkczpTaWduYXR1cmVWYWx1ZT50a2R5UjN6YTJrYlBRQUhXLzZTRXF1UTNMZ24rMzMxVTltWm5yUkZLUDFNbndUdmZEOUdwRXcrNWRWeFF0d3FBSXFEOXAxV3dEcWJpSUQ3YWdUV2FFOGQ4Ym1CazIxS1hieGhNUDcrM0dqdTJNSExiRjlBSEk5TGZCUVZDbEdjZXJ2MkVicm5sRS9tRjNjUEVjYldWcDV4MkV0RDAwcXhkKzFUdzF5ekVPN0xGU3hOK2NwRmYvU1F2cW42Wnl5bjNSenBFSXljQ1Y5RWdYV0xlS3VsNDdyYmFhRWtXWVIxUk54OG82OE9xTlJPQ0FxTUgxR0c3bjRiY29DemorL3BOd1JCVmhsN0Z6RlFGeVdDeU44YnIwMWdRZ2U2MWZMVDcxblJTQ2JpdVRhN084ajdMamRMR0dsZkg5R0VjbEJId0VRRVVGRDZBS1ZEYUpCRWhQbStlenc9PTwvZHM6U2lnbmF0dXJlVmFsdWU%2BPEtleUluZm8geG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiPjxYNTA5RGF0YT48WDUwOUNlcnRpZmljYXRlPk1JSUljRENDQmxpZ0F3SUJBZ0lUTXdBaEtnTENqclVNeDJsaWh3QUFBQ0VxQWpBTkJna3Foa2lHOXcwQkFRd0ZBREJkTVFzd0NRWURWUVFHRXdKVlV6RWVNQndHQTFVRUNoTVZUV2xqY205emIyWjBJRU52Y25CdmNtRjBhVzl1TVM0d0xBWURWUVFERXlWTmFXTnliM052Wm5RZ1FYcDFjbVVnVWxOQklGUk1VeUJKYzNOMWFXNW5JRU5CSURBME1CNFhEVEkwTURFeE5qRTRNVFF5TlZvWERUSTFNREV4TURFNE1UUXlOVm93YlRFTE1Ba0dBMVVFQmhNQ1ZWTXhDekFKQmdOVkJBZ1RBbGRCTVJBd0RnWURWUVFIRXdkU1pXUnRiMjVrTVI0d0hBWURWUVFLRXhWTmFXTnliM052Wm5RZ1EyOXljRzl5WVhScGIyNHhIekFkQmdOVkJBTVRGbTF6Wm5RdWMzUnpMbTFwWTNKdmMyOW1kQzVqYjIwd2dnRWlNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJEd0F3Z2dFS0FvSUJBUURGS2xzVkdYVjlKRk9kVUpPcDQ5emJjSTFVdHl3TUZwNFZyN0RWRFlqemxFazhnRjh3VUpGaHFPYzU2b1pVMGpLQm9BV2tDMHNlZnBmWG1kYXpiN1lzQ0ZqcFVaL3BXZWwwaU5zbURIaUFsK3l0ZnloeWkrQm5rQ0pDckNUSmlhSzJWTnAwUWdZSEpsNktwcFZZRld1QXIzVVZoeUd0Q3hjb1pydVlMQmxiN1VOMlQ2QWJSM2E2V0toRDU4UlJBRGE0RWJlY0NvbjZNdFZ2OUFlUWRpK2l6SzdoaElHZWc1Q1BNdUlFTzAyZCtLZ0FyTGxYQURtM0pPNWllL0p0bm9QU01zQ0FoSlFHcUt4amEyOElsSjRWb3JNalR1VjVsNzB4N1ZVVkJnMkVJZ3ArdmdKOEY1MUtYUGJRS3VKdnlYU0NMRWwrZmY3dFBqRmhpMmkzZ0UvSkFnTUJBQUdqZ2dRWE1JSUVFekNDQVgwR0Npc0dBUVFCMW5rQ0JBSUVnZ0Z0QklJQmFRRm5BSFVBVG5XakoxeWFFTU00VzJ6VTN6OVM2eDN3NEk0YmpXbkFzZnBrc1dLYU9kOEFBQUdORTRTRzFnQUFCQU1BUmpCRUFpQXFYRzNVdFNibGkzZVlVSWxOazhTSVFZVTVKZHhRa2N6b25Pa2FwK2MzT2dJZ01ZMnBaR0JncjdXZEFRQTUwREJUaDhVN09pUTNkUHZtMUorVEp0Vmh4VW9BZGdCOVdSNFM0WGdxZXh4aFozeGUvZmpRaDF3VW9FNlZucmtETDlrT2pDNTV1QUFBQVkwVGhJYXNBQUFFQXdCSE1FVUNJRXJpV0V0Y0tJekNtbTgzTFpLOW03cUg3VXBxVXk4UU1Ld1p0Ty82Mmk2c0FpRUFnNzBBVXNHaE5QYXJBLzVnUE9rTnBNYVd2SWxiN0xqNDlYSXdEUFdyN1ZFQWRnQlZnZFRDRnBBMkFVcnFDNXRYUEZQd3dPUTRlSEFsQ0Jjdm82b2RCeFBUREFBQUFZMFRoSWluQUFBRUF3QkhNRVVDSVFEWEltb0RJaWRIOXBxdFpWcmtQWGJ6MnBhakttaFZ0bEpGOXpPRDhmN0hYZ0lnYVlYOVhjbW5QU3FtajZBZDBqK25CMWYxS0dhb3Uzd2IrQUhJZkE0ZXpBRXdKd1lKS3dZQkJBR0NOeFVLQkJvd0dEQUtCZ2dyQmdFRkJRY0RBakFLQmdnckJnRUZCUWNEQVRBOEJna3JCZ0VFQVlJM0ZRY0VMekF0QmlVckJnRUVBWUkzRlFpSHZkY2JnZWZyUm9LQm5TNk8wQXlIOE5vZFhZS0U1V21DODZjK0FnRmtBZ0VtTUlHMEJnZ3JCZ0VGQlFjQkFRU0JwekNCcERCekJnZ3JCZ0VGQlFjd0FvWm5hSFIwY0RvdkwzZDNkeTV0YVdOeWIzTnZablF1WTI5dEwzQnJhVzl3Y3k5alpYSjBjeTlOYVdOeWIzTnZablFsTWpCQmVuVnlaU1V5TUZKVFFTVXlNRlJNVXlVeU1FbHpjM1ZwYm1jbE1qQkRRU1V5TURBMEpUSXdMU1V5TUhoemFXZHVMbU55ZERBdEJnZ3JCZ0VGQlFjd0FZWWhhSFIwY0RvdkwyOXVaVzlqYzNBdWJXbGpjbTl6YjJaMExtTnZiUzl2WTNOd01CMEdBMVVkRGdRV0JCUVdzdG4vTkhNdzhCMDJzZ0xOY0FMWnhLTU5NVEFPQmdOVkhROEJBZjhFQkFNQ0JhQXdJUVlEVlIwUkJCb3dHSUlXYlhObWRDNXpkSE11YldsamNtOXpiMlowTG1OdmJUQU1CZ05WSFJNQkFmOEVBakFBTUdvR0ExVWRId1JqTUdFd1g2QmRvRnVHV1doMGRIQTZMeTkzZDNjdWJXbGpjbTl6YjJaMExtTnZiUzl3YTJsdmNITXZZM0pzTDAxcFkzSnZjMjltZENVeU1FRjZkWEpsSlRJd1VsTkJKVEl3VkV4VEpUSXdTWE56ZFdsdVp5VXlNRU5CSlRJd01EUXVZM0pzTUdZR0ExVWRJQVJmTUYwd1VRWU1Ld1lCQkFHQ04weURmUUVCTUVFd1B3WUlLd1lCQlFVSEFnRVdNMmgwZEhBNkx5OTNkM2N1YldsamNtOXpiMlowTG1OdmJTOXdhMmx2Y0hNdlJHOWpjeTlTWlhCdmMybDBiM0o1TG1oMGJUQUlCZ1puZ1F3QkFnSXdId1lEVlIwakJCZ3dGb0FVTzNEUlUrbDJKWjFncU1wbUQ4YWJybTlVRm1vd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3SUdDQ3NHQVFVRkJ3TUJNQTBHQ1NxR1NJYjNEUUVCREFVQUE0SUNBUUFFMjlNWDF2WWRXU2xKV3Q4UGlydDhXVGdJanVLSkFmMW9yTE9vM1NQMjdtbHJiNlByQWZtVExYN1VTOG5taVc2bVpGMjl4Vzhnb3ZmWkJNczZ3MFh4d2o3Wjl3RlA2aDhYQ1MvMzh2UkhQZkVTMFBnVkhpUTRYNU41Z0R2azlRQVNXU3RuVzhqVWhaLzFmQ0l3c0Y2dFQ3UnJkM1M3OWFVRjhGRVdWL3M1U0tFM2d1N1BrVzkxQlQ0NG5GcTF6ejNjaWw1Qjc2OEQ0TTBJcDlkY3VaK3RlamtiUGtXVndGaHY2dmx3V3lTeXJ1SUlaNU1lRHpoYUpEaFZqSEQ3V2lGMys2aVVoRUl3T05FM0poVVNSTDF0UjZpZmJGeGhKd1R4b1FtNkxMN21DY3FkRkdGZnNoUlF4OTcxN3RQcFIwbEdWZ3FuWXhsQnd2MmxTZ3pobCttV2p5NEM4dHpnS3RoZ05CaFk1bjdSbWw1RkFqZkE2Y1VQUWg2MHdzMzBBZFNhS0RaOGtWTTFxTEtVb0FkNWhqQi9ad0hGTkZvWVFncjFiZ1Rjc3lsdzRBKzN3dUpPNmYvcjRmWnVvaDNUSmppbDI5MFhGZ3ZwNzZvTGVNeFg3em9uVzNIU2IvY05UZUZMTmVGM3NVYnVRUzBoeE16d25qNmpqSXpGSnhhczU0SlpycGtydjJYcHR6RHZiZWVnM29OQVJHdEc0TkY0TkFmYVRWL2M0QXJHeHRnUWw0V3hlYlU1VXo5UnY5V2tmbEo0bkFpL0RreC85ZGJuUWk3VmtUN2ZCdDBidnI5SGFiNkdmWjYyR3RsRWc2ZWlaNWI4WmlOSFBiMzVIV0tYS0RObnBXb2ljWCtsbVdqZkdBWXRkY1M2NERYM2dtVzN4c28vN1dlNkVLUjNidz09PC9YNTA5Q2VydGlmaWNhdGU%2BPC9YNTA5RGF0YT48L0tleUluZm8%2BPC9kczpTaWduYXR1cmU%2BPC9zYW1sOkFzc2VydGlvbj4%3D&client_id=[REDACTED]&client_info=1&grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Asaml1_1-bearer&password=[REDACTED]&req_cnf=[REDACTED]&scope=6256c85f-0aad-4d50-b960-e6e9b21efe35%2F.default+openid+offline_access+profile&token_type=pop&username=USERNAME + form: + assertion: + - PHNhbWw6QXNzZXJ0aW9uIE1ham9yVmVyc2lvbj0iMSIgTWlub3JWZXJzaW9uPSIxIiBBc3NlcnRpb25JRD0iX2NjNGNjNjJjLTQzZmEtNDA1NC05NWVjLTg5MzFjMDI3N2Y3YSIgSXNzdWVyPSJ1cm46ZmVkZXJhdGlvbjpNU0ZUIiBJc3N1ZUluc3RhbnQ9IjIwMjQtMDItMjFUMjE6MTQ6MjcuNzcwWiIgeG1sbnM6c2FtbD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4wOmFzc2VydGlvbiI+PHNhbWw6Q29uZGl0aW9ucyBOb3RCZWZvcmU9IjIwMjQtMDItMjFUMjE6MTQ6MjcuNzcwWiIgTm90T25PckFmdGVyPSIyMDI0LTAyLTIxVDIyOjE0OjI3Ljc3MFoiPjxzYW1sOkF1ZGllbmNlUmVzdHJpY3Rpb25Db25kaXRpb24+PHNhbWw6QXVkaWVuY2U+dXJuOmZlZGVyYXRpb246TWljcm9zb2Z0T25saW5lPC9zYW1sOkF1ZGllbmNlPjwvc2FtbDpBdWRpZW5jZVJlc3RyaWN0aW9uQ29uZGl0aW9uPjwvc2FtbDpDb25kaXRpb25zPjxzYW1sOkF0dHJpYnV0ZVN0YXRlbWVudD48c2FtbDpTdWJqZWN0PjxzYW1sOk5hbWVJZGVudGlmaWVyIEZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4xOm5hbWVpZC1mb3JtYXQ6dW5zcGVjaWZpZWQiPjRwR0s0dFRoQ2thbUpxQWozM3NoWkE9PTwvc2FtbDpOYW1lSWRlbnRpZmllcj48c2FtbDpTdWJqZWN0Q29uZmlybWF0aW9uPjxzYW1sOkNvbmZpcm1hdGlvbk1ldGhvZD51cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoxLjA6Y206YmVhcmVyPC9zYW1sOkNvbmZpcm1hdGlvbk1ldGhvZD48L3NhbWw6U3ViamVjdENvbmZpcm1hdGlvbj48L3NhbWw6U3ViamVjdD48c2FtbDpBdHRyaWJ1dGUgQXR0cmlidXRlTmFtZT0iVVBOIiBBdHRyaWJ1dGVOYW1lc3BhY2U9Imh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL2NsYWltcyI+PHNhbWw6QXR0cmlidXRlVmFsdWU+azhjb25uZWN0c2FAbWljcm9zb2Z0LmNvbTwvc2FtbDpBdHRyaWJ1dGVWYWx1ZT48L3NhbWw6QXR0cmlidXRlPjxzYW1sOkF0dHJpYnV0ZSBBdHRyaWJ1dGVOYW1lPSJvYmplY3RHVUlEIiBBdHRyaWJ1dGVOYW1lc3BhY2U9Imh0dHA6Ly90ZW1wdXJpLmNvbSI+PHNhbWw6QXR0cmlidXRlVmFsdWU+NHBHSzR0VGhDa2FtSnFBajMzc2haQT09PC9zYW1sOkF0dHJpYnV0ZVZhbHVlPjwvc2FtbDpBdHRyaWJ1dGU+PHNhbWw6QXR0cmlidXRlIEF0dHJpYnV0ZU5hbWU9IlBlcnNvbm5lbE51bWJlciIgQXR0cmlidXRlTmFtZXNwYWNlPSJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy9jbGFpbXMiPjxzYW1sOkF0dHJpYnV0ZVZhbHVlPjRwR0s0dFRoQ2thbUpxQWozM3NoWkE9PTwvc2FtbDpBdHRyaWJ1dGVWYWx1ZT48L3NhbWw6QXR0cmlidXRlPjxzYW1sOkF0dHJpYnV0ZSBBdHRyaWJ1dGVOYW1lPSJJbW11dGFibGVJRCIgQXR0cmlidXRlTmFtZXNwYWNlPSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL0xpdmVJRC9GZWRlcmF0aW9uLzIwMDgvMDUiPjxzYW1sOkF0dHJpYnV0ZVZhbHVlPjRwR0s0dFRoQ2thbUpxQWozM3NoWkE9PTwvc2FtbDpBdHRyaWJ1dGVWYWx1ZT48L3NhbWw6QXR0cmlidXRlPjxzYW1sOkF0dHJpYnV0ZSBBdHRyaWJ1dGVOYW1lPSJhdXRobm1ldGhvZHNyZWZlcmVuY2VzIiBBdHRyaWJ1dGVOYW1lc3BhY2U9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vY2xhaW1zIj48c2FtbDpBdHRyaWJ1dGVWYWx1ZT5odHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvYXV0aGVudGljYXRpb25tZXRob2QvcGFzc3dvcmQ8L3NhbWw6QXR0cmlidXRlVmFsdWU+PC9zYW1sOkF0dHJpYnV0ZT48c2FtbDpBdHRyaWJ1dGUgQXR0cmlidXRlTmFtZT0icGFzc3dvcmRleHBpcmF0aW9udGltZSIgQXR0cmlidXRlTmFtZXNwYWNlPSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMTIvMDEiPjxzYW1sOkF0dHJpYnV0ZVZhbHVlPjIwMjQtMDktMjFUMjE6MDA6MDMuNzU3Wjwvc2FtbDpBdHRyaWJ1dGVWYWx1ZT48L3NhbWw6QXR0cmlidXRlPjxzYW1sOkF0dHJpYnV0ZSBBdHRyaWJ1dGVOYW1lPSJwYXNzd29yZGNoYW5nZXVybCIgQXR0cmlidXRlTmFtZXNwYWNlPSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMTIvMDEiPjxzYW1sOkF0dHJpYnV0ZVZhbHVlPmh0dHBzOi8vc3NwbS5taWNyb3NvZnQuY29tPC9zYW1sOkF0dHJpYnV0ZVZhbHVlPjwvc2FtbDpBdHRyaWJ1dGU+PHNhbWw6QXR0cmlidXRlIEF0dHJpYnV0ZU5hbWU9ImNsaWVudC1yZXF1ZXN0LWlkIiBBdHRyaWJ1dGVOYW1lc3BhY2U9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vMjAxMi8wMS9yZXF1ZXN0Y29udGV4dC9jbGFpbXMiIGE6T3JpZ2luYWxJc3N1ZXI9IkNMSUVOVCBDT05URVhUIiB4bWxuczphPSJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA5LzA5L2lkZW50aXR5L2NsYWltcyI+PHNhbWw6QXR0cmlidXRlVmFsdWU+YjQyNzNjMTUtNjBmZC00YmUxLWI1MzgtMTBkZTQ1YTM4NDNiPC9zYW1sOkF0dHJpYnV0ZVZhbHVlPjwvc2FtbDpBdHRyaWJ1dGU+PC9zYW1sOkF0dHJpYnV0ZVN0YXRlbWVudD48c2FtbDpBdXRoZW50aWNhdGlvblN0YXRlbWVudCBBdXRoZW50aWNhdGlvbk1ldGhvZD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4wOmFtOnBhc3N3b3JkIiBBdXRoZW50aWNhdGlvbkluc3RhbnQ9IjIwMjQtMDItMjFUMjE6MTQ6MjcuNzA3WiI+PHNhbWw6U3ViamVjdD48c2FtbDpOYW1lSWRlbnRpZmllciBGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjEuMTpuYW1laWQtZm9ybWF0OnVuc3BlY2lmaWVkIj40cEdLNHRUaENrYW1KcUFqMzNzaFpBPT08L3NhbWw6TmFtZUlkZW50aWZpZXI+PHNhbWw6U3ViamVjdENvbmZpcm1hdGlvbj48c2FtbDpDb25maXJtYXRpb25NZXRob2Q+dXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4wOmNtOmJlYXJlcjwvc2FtbDpDb25maXJtYXRpb25NZXRob2Q+PC9zYW1sOlN1YmplY3RDb25maXJtYXRpb24+PC9zYW1sOlN1YmplY3Q+PC9zYW1sOkF1dGhlbnRpY2F0aW9uU3RhdGVtZW50PjxkczpTaWduYXR1cmUgeG1sbnM6ZHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiPjxkczpTaWduZWRJbmZvPjxkczpDYW5vbmljYWxpemF0aW9uTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIi8+PGRzOlNpZ25hdHVyZU1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZHNpZy1tb3JlI3JzYS1zaGEyNTYiLz48ZHM6UmVmZXJlbmNlIFVSST0iI19jYzRjYzYyYy00M2ZhLTQwNTQtOTVlYy04OTMxYzAyNzdmN2EiPjxkczpUcmFuc2Zvcm1zPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjZW52ZWxvcGVkLXNpZ25hdHVyZSIvPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiLz48L2RzOlRyYW5zZm9ybXM+PGRzOkRpZ2VzdE1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jI3NoYTI1NiIvPjxkczpEaWdlc3RWYWx1ZT40ei9zWmFWalQvWmhzR2RYUXdWZVlpaEVTcVYrRlh0cVhrYWN5cE8xNWhZPTwvZHM6RGlnZXN0VmFsdWU+PC9kczpSZWZlcmVuY2U+PC9kczpTaWduZWRJbmZvPjxkczpTaWduYXR1cmVWYWx1ZT50a2R5UjN6YTJrYlBRQUhXLzZTRXF1UTNMZ24rMzMxVTltWm5yUkZLUDFNbndUdmZEOUdwRXcrNWRWeFF0d3FBSXFEOXAxV3dEcWJpSUQ3YWdUV2FFOGQ4Ym1CazIxS1hieGhNUDcrM0dqdTJNSExiRjlBSEk5TGZCUVZDbEdjZXJ2MkVicm5sRS9tRjNjUEVjYldWcDV4MkV0RDAwcXhkKzFUdzF5ekVPN0xGU3hOK2NwRmYvU1F2cW42Wnl5bjNSenBFSXljQ1Y5RWdYV0xlS3VsNDdyYmFhRWtXWVIxUk54OG82OE9xTlJPQ0FxTUgxR0c3bjRiY29DemorL3BOd1JCVmhsN0Z6RlFGeVdDeU44YnIwMWdRZ2U2MWZMVDcxblJTQ2JpdVRhN084ajdMamRMR0dsZkg5R0VjbEJId0VRRVVGRDZBS1ZEYUpCRWhQbStlenc9PTwvZHM6U2lnbmF0dXJlVmFsdWU+PEtleUluZm8geG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiPjxYNTA5RGF0YT48WDUwOUNlcnRpZmljYXRlPk1JSUljRENDQmxpZ0F3SUJBZ0lUTXdBaEtnTENqclVNeDJsaWh3QUFBQ0VxQWpBTkJna3Foa2lHOXcwQkFRd0ZBREJkTVFzd0NRWURWUVFHRXdKVlV6RWVNQndHQTFVRUNoTVZUV2xqY205emIyWjBJRU52Y25CdmNtRjBhVzl1TVM0d0xBWURWUVFERXlWTmFXTnliM052Wm5RZ1FYcDFjbVVnVWxOQklGUk1VeUJKYzNOMWFXNW5JRU5CSURBME1CNFhEVEkwTURFeE5qRTRNVFF5TlZvWERUSTFNREV4TURFNE1UUXlOVm93YlRFTE1Ba0dBMVVFQmhNQ1ZWTXhDekFKQmdOVkJBZ1RBbGRCTVJBd0RnWURWUVFIRXdkU1pXUnRiMjVrTVI0d0hBWURWUVFLRXhWTmFXTnliM052Wm5RZ1EyOXljRzl5WVhScGIyNHhIekFkQmdOVkJBTVRGbTF6Wm5RdWMzUnpMbTFwWTNKdmMyOW1kQzVqYjIwd2dnRWlNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJEd0F3Z2dFS0FvSUJBUURGS2xzVkdYVjlKRk9kVUpPcDQ5emJjSTFVdHl3TUZwNFZyN0RWRFlqemxFazhnRjh3VUpGaHFPYzU2b1pVMGpLQm9BV2tDMHNlZnBmWG1kYXpiN1lzQ0ZqcFVaL3BXZWwwaU5zbURIaUFsK3l0ZnloeWkrQm5rQ0pDckNUSmlhSzJWTnAwUWdZSEpsNktwcFZZRld1QXIzVVZoeUd0Q3hjb1pydVlMQmxiN1VOMlQ2QWJSM2E2V0toRDU4UlJBRGE0RWJlY0NvbjZNdFZ2OUFlUWRpK2l6SzdoaElHZWc1Q1BNdUlFTzAyZCtLZ0FyTGxYQURtM0pPNWllL0p0bm9QU01zQ0FoSlFHcUt4amEyOElsSjRWb3JNalR1VjVsNzB4N1ZVVkJnMkVJZ3ArdmdKOEY1MUtYUGJRS3VKdnlYU0NMRWwrZmY3dFBqRmhpMmkzZ0UvSkFnTUJBQUdqZ2dRWE1JSUVFekNDQVgwR0Npc0dBUVFCMW5rQ0JBSUVnZ0Z0QklJQmFRRm5BSFVBVG5XakoxeWFFTU00VzJ6VTN6OVM2eDN3NEk0YmpXbkFzZnBrc1dLYU9kOEFBQUdORTRTRzFnQUFCQU1BUmpCRUFpQXFYRzNVdFNibGkzZVlVSWxOazhTSVFZVTVKZHhRa2N6b25Pa2FwK2MzT2dJZ01ZMnBaR0JncjdXZEFRQTUwREJUaDhVN09pUTNkUHZtMUorVEp0Vmh4VW9BZGdCOVdSNFM0WGdxZXh4aFozeGUvZmpRaDF3VW9FNlZucmtETDlrT2pDNTV1QUFBQVkwVGhJYXNBQUFFQXdCSE1FVUNJRXJpV0V0Y0tJekNtbTgzTFpLOW03cUg3VXBxVXk4UU1Ld1p0Ty82Mmk2c0FpRUFnNzBBVXNHaE5QYXJBLzVnUE9rTnBNYVd2SWxiN0xqNDlYSXdEUFdyN1ZFQWRnQlZnZFRDRnBBMkFVcnFDNXRYUEZQd3dPUTRlSEFsQ0Jjdm82b2RCeFBUREFBQUFZMFRoSWluQUFBRUF3QkhNRVVDSVFEWEltb0RJaWRIOXBxdFpWcmtQWGJ6MnBhakttaFZ0bEpGOXpPRDhmN0hYZ0lnYVlYOVhjbW5QU3FtajZBZDBqK25CMWYxS0dhb3Uzd2IrQUhJZkE0ZXpBRXdKd1lKS3dZQkJBR0NOeFVLQkJvd0dEQUtCZ2dyQmdFRkJRY0RBakFLQmdnckJnRUZCUWNEQVRBOEJna3JCZ0VFQVlJM0ZRY0VMekF0QmlVckJnRUVBWUkzRlFpSHZkY2JnZWZyUm9LQm5TNk8wQXlIOE5vZFhZS0U1V21DODZjK0FnRmtBZ0VtTUlHMEJnZ3JCZ0VGQlFjQkFRU0JwekNCcERCekJnZ3JCZ0VGQlFjd0FvWm5hSFIwY0RvdkwzZDNkeTV0YVdOeWIzTnZablF1WTI5dEwzQnJhVzl3Y3k5alpYSjBjeTlOYVdOeWIzTnZablFsTWpCQmVuVnlaU1V5TUZKVFFTVXlNRlJNVXlVeU1FbHpjM1ZwYm1jbE1qQkRRU1V5TURBMEpUSXdMU1V5TUhoemFXZHVMbU55ZERBdEJnZ3JCZ0VGQlFjd0FZWWhhSFIwY0RvdkwyOXVaVzlqYzNBdWJXbGpjbTl6YjJaMExtTnZiUzl2WTNOd01CMEdBMVVkRGdRV0JCUVdzdG4vTkhNdzhCMDJzZ0xOY0FMWnhLTU5NVEFPQmdOVkhROEJBZjhFQkFNQ0JhQXdJUVlEVlIwUkJCb3dHSUlXYlhObWRDNXpkSE11YldsamNtOXpiMlowTG1OdmJUQU1CZ05WSFJNQkFmOEVBakFBTUdvR0ExVWRId1JqTUdFd1g2QmRvRnVHV1doMGRIQTZMeTkzZDNjdWJXbGpjbTl6YjJaMExtTnZiUzl3YTJsdmNITXZZM0pzTDAxcFkzSnZjMjltZENVeU1FRjZkWEpsSlRJd1VsTkJKVEl3VkV4VEpUSXdTWE56ZFdsdVp5VXlNRU5CSlRJd01EUXVZM0pzTUdZR0ExVWRJQVJmTUYwd1VRWU1Ld1lCQkFHQ04weURmUUVCTUVFd1B3WUlLd1lCQlFVSEFnRVdNMmgwZEhBNkx5OTNkM2N1YldsamNtOXpiMlowTG1OdmJTOXdhMmx2Y0hNdlJHOWpjeTlTWlhCdmMybDBiM0o1TG1oMGJUQUlCZ1puZ1F3QkFnSXdId1lEVlIwakJCZ3dGb0FVTzNEUlUrbDJKWjFncU1wbUQ4YWJybTlVRm1vd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3SUdDQ3NHQVFVRkJ3TUJNQTBHQ1NxR1NJYjNEUUVCREFVQUE0SUNBUUFFMjlNWDF2WWRXU2xKV3Q4UGlydDhXVGdJanVLSkFmMW9yTE9vM1NQMjdtbHJiNlByQWZtVExYN1VTOG5taVc2bVpGMjl4Vzhnb3ZmWkJNczZ3MFh4d2o3Wjl3RlA2aDhYQ1MvMzh2UkhQZkVTMFBnVkhpUTRYNU41Z0R2azlRQVNXU3RuVzhqVWhaLzFmQ0l3c0Y2dFQ3UnJkM1M3OWFVRjhGRVdWL3M1U0tFM2d1N1BrVzkxQlQ0NG5GcTF6ejNjaWw1Qjc2OEQ0TTBJcDlkY3VaK3RlamtiUGtXVndGaHY2dmx3V3lTeXJ1SUlaNU1lRHpoYUpEaFZqSEQ3V2lGMys2aVVoRUl3T05FM0poVVNSTDF0UjZpZmJGeGhKd1R4b1FtNkxMN21DY3FkRkdGZnNoUlF4OTcxN3RQcFIwbEdWZ3FuWXhsQnd2MmxTZ3pobCttV2p5NEM4dHpnS3RoZ05CaFk1bjdSbWw1RkFqZkE2Y1VQUWg2MHdzMzBBZFNhS0RaOGtWTTFxTEtVb0FkNWhqQi9ad0hGTkZvWVFncjFiZ1Rjc3lsdzRBKzN3dUpPNmYvcjRmWnVvaDNUSmppbDI5MFhGZ3ZwNzZvTGVNeFg3em9uVzNIU2IvY05UZUZMTmVGM3NVYnVRUzBoeE16d25qNmpqSXpGSnhhczU0SlpycGtydjJYcHR6RHZiZWVnM29OQVJHdEc0TkY0TkFmYVRWL2M0QXJHeHRnUWw0V3hlYlU1VXo5UnY5V2tmbEo0bkFpL0RreC85ZGJuUWk3VmtUN2ZCdDBidnI5SGFiNkdmWjYyR3RsRWc2ZWlaNWI4WmlOSFBiMzVIV0tYS0RObnBXb2ljWCtsbVdqZkdBWXRkY1M2NERYM2dtVzN4c28vN1dlNkVLUjNidz09PC9YNTA5Q2VydGlmaWNhdGU+PC9YNTA5RGF0YT48L0tleUluZm8+PC9kczpTaWduYXR1cmU+PC9zYW1sOkFzc2VydGlvbj4= + client_id: + - '[REDACTED]' + client_info: + - "1" + grant_type: + - urn:ietf:params:oauth:grant-type:saml1_1-bearer + password: + - '[REDACTED]' + req_cnf: + - '[REDACTED]' + scope: + - '[REDACTED]/.default openid offline_access profile' + token_type: + - pop + username: + - USERNAME + headers: + Accept-Encoding: + - gzip + Client-Request-Id: + - ccb6d130-1f77-495d-b371-3f785ac3cdb6 + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Return-Client-Request-Id: + - "false" + X-Client-Cpu: + - amd64 + X-Client-Os: + - linux + X-Client-Sku: + - MSAL.Go + X-Client-Ver: + - 1.2.0 + url: https://login.microsoftonline.com/AZURE_TENANT_ID/oauth2/v2.0/token + method: POST + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + transfer_encoding: [] + trailer: {} + content_length: 4946 + uncompressed: false + body: '{"token_type":"Bearer","expires_in":86399,"ext_expires_in":86399,"access_token":"TEST_ACCESS_TOKEN"}' + headers: + Cache-Control: + - no-store, no-cache + Client-Request-Id: + - ccb6d130-1f77-495d-b371-3f785ac3cdb6 + Content-Length: + - "4946" + Content-Type: + - application/json; charset=utf-8 + Date: + - Wed, 21 Feb 2024 21:14:28 GMT + Expires: + - "-1" + P3p: + - CP="DSP CUR OTPi IND OTRi ONL FIN" + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + X-Content-Type-Options: + - nosniff + X-Ms-Clitelem: + - 1,0,0,, + X-Ms-Ests-Server: + - 2.1.17396.6 - EUS ProdSlices + X-Xss-Protection: + - "0" + status: 200 OK + code: 200 + duration: 460.493814ms diff --git a/pkg/internal/testutils/govcrutils.go b/pkg/internal/testutils/govcrutils.go index 7807a6cc..5184ba0c 100644 --- a/pkg/internal/testutils/govcrutils.go +++ b/pkg/internal/testutils/govcrutils.go @@ -30,7 +30,13 @@ func GetVCRHttpClient(path string, token string) (*recorder.Recorder, *http.Clie rec, _ := recorder.NewWithOptions(opts) hook := func(i *cassette.Interaction) error { - var detectedClientID, detectedClientSecret, detectedClientAssertion, detectedScope, detectedReqCnf string + var detectedClientID, + detectedClientSecret, + detectedClientAssertion, + detectedScope, + detectedReqCnf, + detectedPassword, + detectedUsername string // Delete sensitive content delete(i.Response.Headers, "Set-Cookie") delete(i.Response.Headers, "X-Ms-Request-Id") @@ -54,6 +60,14 @@ func GetVCRHttpClient(path string, token string) (*recorder.Recorder, *http.Clie detectedScope = i.Request.Form["req_cnf"][0] i.Request.Form["req_cnf"] = []string{redactionToken} } + if i.Request.Form["password"] != nil && i.Request.Form["password"][0] != BadSecret { + detectedPassword = i.Request.Form["password"][0] + i.Request.Form["password"] = []string{redactionToken} + } + if i.Request.Form["username"] != nil { + detectedUsername = i.Request.Form["username"][0] + i.Request.Form["username"] = []string{Username} + } if os.Getenv(tenantUUID) != "" { i.Request.URL = strings.ReplaceAll(i.Request.URL, os.Getenv(tenantUUID), tenantUUID) @@ -64,7 +78,7 @@ func GetVCRHttpClient(path string, token string) (*recorder.Recorder, *http.Clie i.Request.Body = strings.ReplaceAll(i.Request.Body, detectedClientID, redactionToken) } if detectedClientSecret != "" { - i.Request.Body = strings.ReplaceAll(i.Request.Body, detectedClientSecret, redactionToken) + i.Request.Body = ReplaceSecretValuesIncludingURLEscaped(i.Request.Body, detectedClientSecret, redactionToken) } if detectedClientAssertion != "" { i.Request.Body = strings.ReplaceAll(i.Request.Body, detectedClientAssertion, redactionToken) @@ -75,6 +89,13 @@ func GetVCRHttpClient(path string, token string) (*recorder.Recorder, *http.Clie if detectedReqCnf != "" { i.Request.Body = strings.ReplaceAll(i.Request.Body, detectedReqCnf, redactionToken) } + if detectedPassword != "" { + i.Request.Body = ReplaceSecretValuesIncludingURLEscaped(i.Request.Body, detectedPassword, redactionToken) + } + if detectedUsername != "" { + i.Request.Body = ReplaceSecretValuesIncludingURLEscaped(i.Request.Body, detectedUsername, Username) + i.Request.URL = ReplaceSecretValuesIncludingURLEscaped(i.Request.URL, detectedUsername, Username) + } if strings.Contains(i.Response.Body, "access_token") { i.Response.Body = `{"token_type":"Bearer","expires_in":86399,"ext_expires_in":86399,"access_token":"` + testToken + `"}` diff --git a/pkg/internal/testutils/testutils.go b/pkg/internal/testutils/testutils.go index dca27fb2..d0621cd9 100644 --- a/pkg/internal/testutils/testutils.go +++ b/pkg/internal/testutils/testutils.go @@ -1,6 +1,9 @@ package testutils -import "strings" +import ( + "net/url" + "strings" +) const ( ClientID = "AZURE_CLIENT_ID" @@ -10,6 +13,8 @@ const ( ResourceID = "AZURE_RESOURCE_ID" TenantID = "AZURE_TENANT_ID" BadSecret = "Bad_Secret" + Username = "USERNAME" + Password = "PASSWORD" ) // ErrorContains takes an input error and a desired substring, checks if the string is present @@ -24,3 +29,17 @@ func ErrorContains(out error, want string) bool { } return strings.Contains(out.Error(), substring) } + +// ReplaceSecretValuesIncludingURLEscaped takes an input string, finds any instances of the +// input secret in the string (including in URL-escaped format), and replaces all instances +// with the given redaction token +// This is used for VCR tests as they sometimes include a URL-escaped version of the secret +// in the request body +func ReplaceSecretValuesIncludingURLEscaped(body, secret, redactionToken string) string { + body = strings.ReplaceAll(body, secret, redactionToken) + // get the URL-escaped version of the secret which replaces special characters with + // the URL-safe "%AB" format + escapedSecret := url.QueryEscape(secret) + body = strings.ReplaceAll(body, escapedSecret, redactionToken) + return body +} diff --git a/pkg/internal/testutils/testutils_test.go b/pkg/internal/testutils/testutils_test.go index 3be35dba..24ce806f 100644 --- a/pkg/internal/testutils/testutils_test.go +++ b/pkg/internal/testutils/testutils_test.go @@ -77,3 +77,38 @@ func TestErrorContains(t *testing.T) { }) } } + +func TestReplaceSecretValuesIncludingURLEscaped(t *testing.T) { + testCase := []struct { + name string + body string + secret string + expectedResult string + }{ + { + name: "TestReplaceMultipleSecretValuesWithNonEscapedString", + body: "This is a test request body. ABC123. This is the rest of the request body. ThisABC123 is another line.", + secret: "ABC123", + expectedResult: "This is a test request body. [REDACTED]. This is the rest of the request body. This[REDACTED] is another line.", + }, + { + name: "TestReplaceMultipleSecretValuesWithStringEscape", + body: "This is a test request body. Q#4@6:=. This is the rest of the request body. ThisQ%234%406%3A%3D is another line.", + secret: "Q#4@6:=", + expectedResult: "This is a test request body. [REDACTED]. This is the rest of the request body. This[REDACTED] is another line.", + }, + } + + for _, tc := range testCase { + t.Run(tc.name, func(t *testing.T) { + result := ReplaceSecretValuesIncludingURLEscaped(tc.body, tc.secret, redactionToken) + if result != tc.expectedResult { + t.Errorf( + "expected redaction of secret as \n%s\n but got \n%s\n", + tc.expectedResult, + result, + ) + } + }) + } +} diff --git a/pkg/internal/token/provider.go b/pkg/internal/token/provider.go index 03bac6f1..c9446e1a 100644 --- a/pkg/internal/token/provider.go +++ b/pkg/internal/token/provider.go @@ -41,7 +41,7 @@ func NewTokenProvider(o *Options) (TokenProvider, error) { } return newServicePrincipalTokenProvider(cloudConfiguration, o.ClientID, o.ClientSecret, o.ClientCert, o.ClientCertPassword, o.ServerID, o.TenantID, popClaimsMap) case ROPCLogin: - return newResourceOwnerToken(*oAuthConfig, o.ClientID, o.Username, o.Password, o.ServerID, o.TenantID) + return newResourceOwnerTokenProvider(*oAuthConfig, o.ClientID, o.Username, o.Password, o.ServerID, o.TenantID, popClaimsMap) case MSILogin: return newManagedIdentityToken(o.ClientID, o.IdentityResourceID, o.ServerID) case AzureCLILogin: diff --git a/pkg/internal/token/ropc.go b/pkg/internal/token/ropc.go index eb2fdf89..e719ec1f 100644 --- a/pkg/internal/token/ropc.go +++ b/pkg/internal/token/ropc.go @@ -2,10 +2,15 @@ package token import ( "context" + "encoding/json" "errors" "fmt" + "strconv" + "github.com/Azure/azure-sdk-for-go/sdk/azcore" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud" "github.com/Azure/go-autorest/autorest/adal" + "github.com/Azure/kubelogin/pkg/internal/pop" ) type resourceOwnerToken struct { @@ -15,9 +20,18 @@ type resourceOwnerToken struct { resourceID string tenantID string oAuthConfig adal.OAuthConfig + popClaims map[string]string } -func newResourceOwnerToken(oAuthConfig adal.OAuthConfig, clientID, username, password, resourceID, tenantID string) (TokenProvider, error) { +func newResourceOwnerTokenProvider( + oAuthConfig adal.OAuthConfig, + clientID, + username, + password, + resourceID, + tenantID string, + popClaims map[string]string, +) (TokenProvider, error) { if clientID == "" { return nil, errors.New("clientID cannot be empty") } @@ -41,11 +55,57 @@ func newResourceOwnerToken(oAuthConfig adal.OAuthConfig, clientID, username, pas resourceID: resourceID, tenantID: tenantID, oAuthConfig: oAuthConfig, + popClaims: popClaims, }, nil } +// Token fetches an azcore.AccessToken from the Azure SDK and converts it to an adal.Token for use with kubelogin. func (p *resourceOwnerToken) Token(ctx context.Context) (adal.Token, error) { + return p.tokenWithOptions(ctx, nil) +} + +func (p *resourceOwnerToken) tokenWithOptions(ctx context.Context, options *azcore.ClientOptions) (adal.Token, error) { emptyToken := adal.Token{} + authorityFromConfig := p.oAuthConfig.AuthorityEndpoint + clientOpts := azcore.ClientOptions{Cloud: cloud.Configuration{ + ActiveDirectoryAuthorityHost: authorityFromConfig.String(), + }} + if options != nil { + clientOpts = *options + } + var err error + scopes := []string{p.resourceID + defaultScope} + if len(p.popClaims) > 0 { + // If PoP token support is enabled and the correct u-claim is provided, use the MSAL + // token provider to acquire a new token + token, expirationTimeUnix, err := pop.AcquirePoPTokenByUsernamePassword( + ctx, + p.popClaims, + scopes, + authorityFromConfig.String(), + p.clientID, + p.username, + p.password, + &clientOpts, + ) + if err != nil { + return emptyToken, fmt.Errorf("failed to create PoP token using resource owner flow: %w", err) + } + + // azurecore.AccessTokens have ExpiresOn as Time.Time. We need to convert it to JSON.Number + // by fetching the time in seconds since the Unix epoch via Unix() and then converting to a + // JSON.Number via formatting as a string using a base-10 int64 conversion. + expiresOn := json.Number(strconv.FormatInt(expirationTimeUnix, 10)) + + // Re-wrap the azurecore.AccessToken into an adal.Token + return adal.Token{ + AccessToken: token, + ExpiresOn: expiresOn, + Resource: p.resourceID, + }, nil + } + + // otherwise, if PoP token flow is not enabled, use the default flow callback := func(t adal.Token) error { return nil } diff --git a/pkg/internal/token/ropc_test.go b/pkg/internal/token/ropc_test.go new file mode 100644 index 00000000..5978cad7 --- /dev/null +++ b/pkg/internal/token/ropc_test.go @@ -0,0 +1,235 @@ +package token + +import ( + "context" + "fmt" + "net/url" + "os" + "testing" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud" + "github.com/Azure/go-autorest/autorest/adal" + "github.com/Azure/kubelogin/pkg/internal/testutils" + "github.com/golang-jwt/jwt/v5" + "github.com/google/go-cmp/cmp" + "github.com/google/uuid" + "gopkg.in/dnaeon/go-vcr.v3/recorder" +) + +func TestNewResourceOwnerTokenProvider(t *testing.T) { + testCases := []struct { + name string + clientID string + resourceID string + tenantID string + popClaims map[string]string + username string + password string + expectedError string + }{ + { + name: "test new resource owner token provider with empty client ID should return error", + expectedError: "clientID cannot be empty", + }, + { + name: "test new resource owner token provider with empty username should return error", + clientID: "testclientid", + expectedError: "username cannot be empty", + }, + { + name: "test new resource owner token provider with empty password should return error", + clientID: "testclientid", + username: "testusername", + expectedError: "password cannot be empty", + }, + { + name: "test new resource owner token provider with empty resource ID should return error", + clientID: "testclientid", + username: "testusername", + password: "testpassword", + expectedError: "resourceID cannot be empty", + }, + { + name: "test new resource owner token provider with empty tenant ID should return error", + clientID: "testclientid", + username: "testusername", + password: "testpassword", + resourceID: "testresource", + expectedError: "tenantID cannot be empty", + }, + { + name: "test new resource owner token provider with no pop claims should not return error", + clientID: "testclientid", + username: "testusername", + password: "testpassword", + resourceID: "testresource", + tenantID: "testtenant", + expectedError: "", + }, + { + name: "test new resource owner token provider with pop claims should not return error", + clientID: "testclientid", + username: "testusername", + password: "testpassword", + resourceID: "testresource", + tenantID: "testtenant", + popClaims: map[string]string{"u": "testhost"}, + expectedError: "", + }, + } + var tokenProvider TokenProvider + var err error + oauthConfig := adal.OAuthConfig{} + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + tokenProvider, err = newResourceOwnerTokenProvider( + oauthConfig, + tc.clientID, + tc.username, + tc.password, + tc.resourceID, + tc.tenantID, + tc.popClaims, + ) + + if tc.expectedError != "" { + if !testutils.ErrorContains(err, tc.expectedError) { + t.Errorf("expected error %s, but got %s", tc.expectedError, err) + } + } else { + if tokenProvider == nil { + t.Errorf("expected token provider creation to succeed, but got error: %s", err) + } + rop := tokenProvider.(*resourceOwnerToken) + if rop.clientID != tc.clientID { + t.Errorf("expected client ID: %s but got: %s", tc.clientID, rop.clientID) + } + if rop.username != tc.username { + t.Errorf("expected username: %s but got: %s", tc.username, rop.username) + } + if rop.password != tc.password { + t.Errorf("expected password: %s but got: %s", tc.password, rop.password) + } + if rop.resourceID != tc.resourceID { + t.Errorf("expected resource ID: %s but got: %s", tc.resourceID, rop.resourceID) + } + if rop.tenantID != tc.tenantID { + t.Errorf("expected tenant ID: %s but got: %s", tc.tenantID, rop.tenantID) + } + if !cmp.Equal(rop.popClaims, tc.popClaims) { + t.Errorf("expected PoP claims: %s but got: %s", tc.popClaims, rop.popClaims) + } + } + }) + } +} + +func TestROPCPoPTokenVCR(t *testing.T) { + pEnv := &resourceOwnerToken{ + clientID: os.Getenv(testutils.ClientID), + username: os.Getenv(testutils.Username), + password: os.Getenv(testutils.Password), + resourceID: os.Getenv(testutils.ResourceID), + tenantID: os.Getenv(testutils.TenantID), + } + // Use defaults if environment variables are empty + if pEnv.clientID == "" { + pEnv.clientID = testutils.ClientID + } + if pEnv.username == "" { + pEnv.username = testutils.Username + } + if pEnv.password == "" { + pEnv.password = testutils.Password + } + if pEnv.resourceID == "" { + pEnv.resourceID = testutils.ResourceID + } + if pEnv.tenantID == "" { + pEnv.tenantID = "00000000-0000-0000-0000-000000000000" + } + + var expectedToken string + var err error + var token adal.Token + expectedTokenType := "pop" + authorityEndpoint, err := url.Parse("https://login.microsoftonline.com/" + pEnv.tenantID) + if err != nil { + t.Errorf("error encountered when parsing active directory endpoint: %s", err) + } + testCase := []struct { + cassetteName string + p *resourceOwnerToken + expectedError error + }{ + { + // Test using bad password + cassetteName: "ROPCPoPTokenFromBadPasswordVCR", + p: &resourceOwnerToken{ + clientID: pEnv.clientID, + username: pEnv.username, + password: testutils.BadSecret, + resourceID: pEnv.resourceID, + tenantID: pEnv.tenantID, + popClaims: map[string]string{"u": "testhost"}, + oAuthConfig: adal.OAuthConfig{ + AuthorityEndpoint: *authorityEndpoint, + }, + }, + expectedError: fmt.Errorf("failed to create PoP token using resource owner flow"), + }, + { + // Test using ROPC username + password to get PoP token + cassetteName: "ROPCPoPTokenFromUsernamePasswordVCR", + p: &resourceOwnerToken{ + clientID: pEnv.clientID, + username: pEnv.username, + password: pEnv.password, + resourceID: pEnv.resourceID, + tenantID: pEnv.tenantID, + popClaims: map[string]string{"u": "testhost"}, + oAuthConfig: adal.OAuthConfig{ + AuthorityEndpoint: *authorityEndpoint, + }, + }, + expectedError: nil, + }, + } + + for _, tc := range testCase { + t.Run(tc.cassetteName, func(t *testing.T) { + if tc.expectedError == nil { + expectedToken = uuid.New().String() + } + vcrRecorder, httpClient := testutils.GetVCRHttpClient(fmt.Sprintf("testdata/%s", tc.cassetteName), expectedToken) + + clientOpts := azcore.ClientOptions{ + Cloud: cloud.AzurePublic, + Transport: httpClient, + } + + token, err = tc.p.tokenWithOptions(context.TODO(), &clientOpts) + defer vcrRecorder.Stop() + if err != nil { + if !testutils.ErrorContains(err, tc.expectedError.Error()) { + t.Errorf("expected error %s, but got %s", tc.expectedError.Error(), err) + } + } else { + if token.AccessToken == "" { + t.Error("expected valid token, but received empty token.") + } + claims := jwt.MapClaims{} + parsed, _ := jwt.ParseWithClaims(token.AccessToken, &claims, nil) + if vcrRecorder.Mode() == recorder.ModeReplayOnly { + if claims["at"] != expectedToken { + t.Errorf("unexpected token returned (expected %s, but got %s)", expectedToken, claims["at"]) + } + if parsed.Header["typ"] != expectedTokenType { + t.Errorf("unexpected token returned (expected %s, but got %s)", expectedTokenType, parsed.Header["typ"]) + } + } + } + }) + } +} diff --git a/pkg/internal/token/testdata/ROPCPoPTokenFromBadPasswordVCR.yaml b/pkg/internal/token/testdata/ROPCPoPTokenFromBadPasswordVCR.yaml new file mode 100644 index 00000000..bb3393ac --- /dev/null +++ b/pkg/internal/token/testdata/ROPCPoPTokenFromBadPasswordVCR.yaml @@ -0,0 +1,247 @@ +--- +version: 2 +interactions: + - id: 0 + request: + proto: "" + proto_major: 0 + proto_minor: 0 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: "" + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Accept-Encoding: + - gzip + Client-Request-Id: + - ba3e5a11-94d7-46c3-8e54-13364f55dd79 + Return-Client-Request-Id: + - "false" + X-Client-Cpu: + - amd64 + X-Client-Os: + - linux + X-Client-Sku: + - MSAL.Go + X-Client-Ver: + - 1.2.0 + url: https://login.microsoftonline.com/AZURE_TENANT_ID/v2.0/.well-known/openid-configuration + method: GET + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + transfer_encoding: [] + trailer: {} + content_length: 1753 + uncompressed: false + body: '{"token_endpoint":"https://login.microsoftonline.com/AZURE_TENANT_ID/oauth2/v2.0/token","token_endpoint_auth_methods_supported":["client_secret_post","private_key_jwt","client_secret_basic"],"jwks_uri":"https://login.microsoftonline.com/AZURE_TENANT_ID/discovery/v2.0/keys","response_modes_supported":["query","fragment","form_post"],"subject_types_supported":["pairwise"],"id_token_signing_alg_values_supported":["RS256"],"response_types_supported":["code","id_token","code id_token","id_token token"],"scopes_supported":["openid","profile","email","offline_access"],"issuer":"https://login.microsoftonline.com/AZURE_TENANT_ID/v2.0","request_uri_parameter_supported":false,"userinfo_endpoint":"https://graph.microsoft.com/oidc/userinfo","authorization_endpoint":"https://login.microsoftonline.com/AZURE_TENANT_ID/oauth2/v2.0/authorize","device_authorization_endpoint":"https://login.microsoftonline.com/AZURE_TENANT_ID/oauth2/v2.0/devicecode","http_logout_supported":true,"frontchannel_logout_supported":true,"end_session_endpoint":"https://login.microsoftonline.com/AZURE_TENANT_ID/oauth2/v2.0/logout","claims_supported":["sub","iss","cloud_instance_name","cloud_instance_host_name","cloud_graph_host_name","msgraph_host","aud","exp","iat","auth_time","acr","nonce","preferred_username","name","tid","ver","at_hash","c_hash","email"],"kerberos_endpoint":"https://login.microsoftonline.com/AZURE_TENANT_ID/kerberos","tenant_region_scope":"WW","cloud_instance_name":"microsoftonline.com","cloud_graph_host_name":"graph.windows.net","msgraph_host":"graph.microsoft.com","rbac_url":"https://pas.windows.net"}' + headers: + Access-Control-Allow-Methods: + - GET, OPTIONS + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=86400, private + Client-Request-Id: + - ba3e5a11-94d7-46c3-8e54-13364f55dd79 + Content-Length: + - "1753" + Content-Type: + - application/json; charset=utf-8 + Date: + - Wed, 21 Feb 2024 20:40:57 GMT + P3p: + - CP="DSP CUR OTPi IND OTRi ONL FIN" + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + X-Content-Type-Options: + - nosniff + X-Ms-Ests-Server: + - 2.1.17396.6 - SCUS ProdSlices + X-Xss-Protection: + - "0" + status: 200 OK + code: 200 + duration: 81.323235ms + - id: 1 + request: + proto: "" + proto_major: 0 + proto_minor: 0 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: "" + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Accept-Encoding: + - gzip + Client-Request-Id: + - 69e8d1ed-503d-4bb3-b1f2-32b9f9de0bf9 + Return-Client-Request-Id: + - "false" + X-Client-Cpu: + - amd64 + X-Client-Os: + - linux + X-Client-Sku: + - MSAL.Go + X-Client-Ver: + - 1.2.0 + client-request-id: + - 328c52b5-e691-4fb6-ae3b-6a77be19685a + url: https://login.microsoftonline.com/common/UserRealm/USERNAME?api-version=1.0 + method: GET + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + transfer_encoding: [] + trailer: {} + content_length: 384 + uncompressed: false + body: '{"ver":"1.0","account_type":"Federated","domain_name":"microsoft.com","federation_protocol":"WSTrust","federation_metadata_url":"https://msft.sts.microsoft.com/adfs/services/trust/mex","federation_active_auth_url":"https://msft.sts.microsoft.com/adfs/services/trust/2005/usernamemixed","cloud_instance_name":"microsoftonline.com","cloud_audience_urn":"urn:federation:MicrosoftOnline"}' + headers: + Cache-Control: + - no-store, no-cache + Content-Disposition: + - inline; filename=userrealm.json + Content-Length: + - "384" + Content-Type: + - application/json; charset=utf-8 + Date: + - Wed, 21 Feb 2024 20:40:57 GMT + Expires: + - "-1" + P3p: + - CP="DSP CUR OTPi IND OTRi ONL FIN" + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + X-Content-Type-Options: + - nosniff + X-Ms-Ests-Server: + - 2.1.17396.6 - NCUS ProdSlices + X-Xss-Protection: + - "0" + status: 200 OK + code: 200 + duration: 47.841162ms + - id: 2 + request: + proto: "" + proto_major: 0 + proto_minor: 0 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: "" + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Accept-Encoding: + - gzip + Client-Request-Id: + - c44580ab-5de8-4799-acd2-020ee532363c + Content-Type: + - application/xml; charset=utf-8 + Return-Client-Request-Id: + - "false" + X-Client-Cpu: + - amd64 + X-Client-Os: + - linux + X-Client-Sku: + - MSAL.Go + X-Client-Ver: + - 1.2.0 + url: https://msft.sts.microsoft.com/adfs/services/trust/mex + method: GET + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + transfer_encoding: [] + trailer: {} + content_length: 14784 + uncompressed: false + body: https://msft.sts.microsoft.com/adfs/services/trust/2005/certificatemixedhttps://certauth.msft.sts.microsoft.com/adfs/services/trust/2005/certificatetransporthttps://msft.sts.microsoft.com/adfs/services/trust/2005/usernamemixedhttps://msft.sts.microsoft.com/adfs/services/trust/13/certificatemixedhttps://msft.sts.microsoft.com/adfs/services/trust/13/usernamemixed + headers: + Content-Length: + - "14784" + Content-Type: + - text/xml; charset=UTF-8 + Date: + - Wed, 21 Feb 2024 20:40:56 GMT + Server: + - Microsoft-HTTPAPI/2.0 Microsoft-HTTPAPI/2.0 + status: 200 OK + code: 200 + duration: 301.203159ms + - id: 3 + request: + proto: "" + proto_major: 0 + proto_minor: 0 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: "" + remote_addr: "" + request_uri: "" + body: http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issueurn:uuid:f9b38faa-c86c-4406-b23b-9bad9cac7200http://www.w3.org/2005/08/addressing/anonymoushttps://msft.sts.microsoft.com/adfs/services/trust/13/usernamemixed2024-02-21T20:40:58.224Z2024-02-21T20:50:58.224ZUSERNAMEBad_Secreturn:federation:MicrosoftOnlinehttp://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearerhttp://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue + form: {} + headers: + Accept-Encoding: + - gzip + Client-Request-Id: + - a7f0c87e-ee41-4594-9fa3-ad549f84854f + Content-Type: + - application/soap+xml; charset=utf-8 + Return-Client-Request-Id: + - "false" + Soapaction: + - http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue + X-Client-Cpu: + - amd64 + X-Client-Os: + - linux + X-Client-Sku: + - MSAL.Go + X-Client-Ver: + - 1.2.0 + url: https://msft.sts.microsoft.com/adfs/services/trust/13/usernamemixed + method: POST + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + transfer_encoding: [] + trailer: {} + content_length: 953 + uncompressed: false + body: 'http://www.w3.org/2005/08/addressing/soap/fault2024-02-21T20:40:58.823Z2024-02-21T20:45:58.823Zs:Sendera:FailedAuthenticationID3242: The security token could not be authenticated or authorized.' + headers: + Content-Length: + - "953" + Content-Type: + - application/soap+xml; charset=utf-8 + Date: + - Wed, 21 Feb 2024 20:40:58 GMT + Server: + - Microsoft-HTTPAPI/2.0 Microsoft-HTTPAPI/2.0 + status: 500 Internal Server Error + code: 500 + duration: 661.204571ms diff --git a/pkg/internal/token/testdata/ROPCPoPTokenFromUsernamePasswordVCR.yaml b/pkg/internal/token/testdata/ROPCPoPTokenFromUsernamePasswordVCR.yaml new file mode 100644 index 00000000..dfc9a3b0 --- /dev/null +++ b/pkg/internal/token/testdata/ROPCPoPTokenFromUsernamePasswordVCR.yaml @@ -0,0 +1,336 @@ +--- +version: 2 +interactions: + - id: 0 + request: + proto: "" + proto_major: 0 + proto_minor: 0 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: "" + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Accept-Encoding: + - gzip + Client-Request-Id: + - 328a1343-bdd7-4e03-9e09-00a9bc3c92f7 + Return-Client-Request-Id: + - "false" + X-Client-Cpu: + - amd64 + X-Client-Os: + - linux + X-Client-Sku: + - MSAL.Go + X-Client-Ver: + - 1.2.0 + url: https://login.microsoftonline.com/AZURE_TENANT_ID/v2.0/.well-known/openid-configuration + method: GET + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + transfer_encoding: [] + trailer: {} + content_length: 1753 + uncompressed: false + body: '{"token_endpoint":"https://login.microsoftonline.com/AZURE_TENANT_ID/oauth2/v2.0/token","token_endpoint_auth_methods_supported":["client_secret_post","private_key_jwt","client_secret_basic"],"jwks_uri":"https://login.microsoftonline.com/AZURE_TENANT_ID/discovery/v2.0/keys","response_modes_supported":["query","fragment","form_post"],"subject_types_supported":["pairwise"],"id_token_signing_alg_values_supported":["RS256"],"response_types_supported":["code","id_token","code id_token","id_token token"],"scopes_supported":["openid","profile","email","offline_access"],"issuer":"https://login.microsoftonline.com/AZURE_TENANT_ID/v2.0","request_uri_parameter_supported":false,"userinfo_endpoint":"https://graph.microsoft.com/oidc/userinfo","authorization_endpoint":"https://login.microsoftonline.com/AZURE_TENANT_ID/oauth2/v2.0/authorize","device_authorization_endpoint":"https://login.microsoftonline.com/AZURE_TENANT_ID/oauth2/v2.0/devicecode","http_logout_supported":true,"frontchannel_logout_supported":true,"end_session_endpoint":"https://login.microsoftonline.com/AZURE_TENANT_ID/oauth2/v2.0/logout","claims_supported":["sub","iss","cloud_instance_name","cloud_instance_host_name","cloud_graph_host_name","msgraph_host","aud","exp","iat","auth_time","acr","nonce","preferred_username","name","tid","ver","at_hash","c_hash","email"],"kerberos_endpoint":"https://login.microsoftonline.com/AZURE_TENANT_ID/kerberos","tenant_region_scope":"WW","cloud_instance_name":"microsoftonline.com","cloud_graph_host_name":"graph.windows.net","msgraph_host":"graph.microsoft.com","rbac_url":"https://pas.windows.net"}' + headers: + Access-Control-Allow-Methods: + - GET, OPTIONS + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=86400, private + Client-Request-Id: + - 328a1343-bdd7-4e03-9e09-00a9bc3c92f7 + Content-Length: + - "1753" + Content-Type: + - application/json; charset=utf-8 + Date: + - Wed, 21 Feb 2024 20:40:59 GMT + P3p: + - CP="DSP CUR OTPi IND OTRi ONL FIN" + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + X-Content-Type-Options: + - nosniff + X-Ms-Ests-Server: + - 2.1.17396.6 - WUS3 ProdSlices + X-Xss-Protection: + - "0" + status: 200 OK + code: 200 + duration: 56.002455ms + - id: 1 + request: + proto: "" + proto_major: 0 + proto_minor: 0 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: "" + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Accept-Encoding: + - gzip + Client-Request-Id: + - be2701ff-dc70-4362-a7f3-073254514b07 + Return-Client-Request-Id: + - "false" + X-Client-Cpu: + - amd64 + X-Client-Os: + - linux + X-Client-Sku: + - MSAL.Go + X-Client-Ver: + - 1.2.0 + client-request-id: + - 86856daf-9e0c-41c4-8de4-01000d99d7bc + url: https://login.microsoftonline.com/common/UserRealm/USERNAME?api-version=1.0 + method: GET + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + transfer_encoding: [] + trailer: {} + content_length: 384 + uncompressed: false + body: '{"ver":"1.0","account_type":"Federated","domain_name":"microsoft.com","federation_protocol":"WSTrust","federation_metadata_url":"https://msft.sts.microsoft.com/adfs/services/trust/mex","federation_active_auth_url":"https://msft.sts.microsoft.com/adfs/services/trust/2005/usernamemixed","cloud_instance_name":"microsoftonline.com","cloud_audience_urn":"urn:federation:MicrosoftOnline"}' + headers: + Cache-Control: + - no-store, no-cache + Content-Disposition: + - inline; filename=userrealm.json + Content-Length: + - "384" + Content-Type: + - application/json; charset=utf-8 + Date: + - Wed, 21 Feb 2024 20:40:59 GMT + Expires: + - "-1" + P3p: + - CP="DSP CUR OTPi IND OTRi ONL FIN" + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + X-Content-Type-Options: + - nosniff + X-Ms-Ests-Server: + - 2.1.17396.6 - SCUS ProdSlices + X-Xss-Protection: + - "0" + status: 200 OK + code: 200 + duration: 62.922549ms + - id: 2 + request: + proto: "" + proto_major: 0 + proto_minor: 0 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: "" + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Accept-Encoding: + - gzip + Client-Request-Id: + - 1b21d2c4-db2d-48d8-bdfc-2cdf4b9c04e8 + Content-Type: + - application/xml; charset=utf-8 + Return-Client-Request-Id: + - "false" + X-Client-Cpu: + - amd64 + X-Client-Os: + - linux + X-Client-Sku: + - MSAL.Go + X-Client-Ver: + - 1.2.0 + url: https://msft.sts.microsoft.com/adfs/services/trust/mex + method: GET + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + transfer_encoding: [] + trailer: {} + content_length: 14784 + uncompressed: false + body: https://msft.sts.microsoft.com/adfs/services/trust/2005/certificatemixedhttps://certauth.msft.sts.microsoft.com/adfs/services/trust/2005/certificatetransporthttps://msft.sts.microsoft.com/adfs/services/trust/2005/usernamemixedhttps://msft.sts.microsoft.com/adfs/services/trust/13/certificatemixedhttps://msft.sts.microsoft.com/adfs/services/trust/13/usernamemixed + headers: + Content-Length: + - "14784" + Content-Type: + - text/xml; charset=UTF-8 + Date: + - Wed, 21 Feb 2024 20:40:59 GMT + Server: + - Microsoft-HTTPAPI/2.0 Microsoft-HTTPAPI/2.0 + status: 200 OK + code: 200 + duration: 75.624339ms + - id: 3 + request: + proto: "" + proto_major: 0 + proto_minor: 0 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: "" + remote_addr: "" + request_uri: "" + body: http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issueurn:uuid:3ca9a32f-2565-4590-adcc-32832b543e2bhttp://www.w3.org/2005/08/addressing/anonymoushttps://msft.sts.microsoft.com/adfs/services/trust/13/usernamemixed2024-02-21T20:41:00.070Z2024-02-21T20:51:00.070ZUSERNAME[REDACTED]urn:federation:MicrosoftOnlinehttp://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearerhttp://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue + form: {} + headers: + Accept-Encoding: + - gzip + Client-Request-Id: + - 433323ed-3edf-419b-bf51-76b7a03bce47 + Content-Type: + - application/soap+xml; charset=utf-8 + Return-Client-Request-Id: + - "false" + Soapaction: + - http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue + X-Client-Cpu: + - amd64 + X-Client-Os: + - linux + X-Client-Sku: + - MSAL.Go + X-Client-Ver: + - 1.2.0 + url: https://msft.sts.microsoft.com/adfs/services/trust/13/usernamemixed + method: POST + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + transfer_encoding: [] + trailer: {} + content_length: 9894 + uncompressed: false + body: http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTRC/IssueFinal2024-02-21T20:41:01.385Z2024-02-21T20:46:01.385Z2024-02-21T20:41:01.026Z2024-02-21T21:41:01.026Zurn:federation:MicrosoftOnlineurn:federation:MicrosoftOnline4pGK4tThCkamJqAj33shZA==urn:oasis:names:tc:SAML:1.0:cm:bearerUSERNAME4pGK4tThCkamJqAj33shZA==4pGK4tThCkamJqAj33shZA==4pGK4tThCkamJqAj33shZA==http://schemas.microsoft.com/ws/2008/06/identity/authenticationmethod/password2024-09-21T21:00:03.757Zhttps://sspm.microsoft.com433323ed-3edf-419b-bf51-76b7a03bce474pGK4tThCkamJqAj33shZA==urn:oasis:names:tc:SAML:1.0:cm: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_c86e011a-8956-4d61-ac24-128649973c64_c86e011a-8956-4d61-ac24-128649973c64urn:oasis:names:tc:SAML:1.0:assertionhttp://docs.oasis-open.org/ws-sx/ws-trust/200512/Issuehttp://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer + headers: + Content-Length: + - "9894" + Content-Type: + - application/soap+xml; charset=utf-8 + Date: + - Wed, 21 Feb 2024 20:41:01 GMT + Server: + - Microsoft-HTTPAPI/2.0 Microsoft-HTTPAPI/2.0 + status: 200 OK + code: 200 + duration: 1.375846499s + - id: 4 + request: + proto: "" + proto_major: 0 + proto_minor: 0 + content_length: 9902 + transfer_encoding: [] + trailer: {} + host: "" + remote_addr: "" + request_uri: "" + body: assertion=PHNhbWw6QXNzZXJ0aW9uIE1ham9yVmVyc2lvbj0iMSIgTWlub3JWZXJzaW9uPSIxIiBBc3NlcnRpb25JRD0iX2M4NmUwMTFhLTg5NTYtNGQ2MS1hYzI0LTEyODY0OTk3M2M2NCIgSXNzdWVyPSJ1cm46ZmVkZXJhdGlvbjpNU0ZUIiBJc3N1ZUluc3RhbnQ9IjIwMjQtMDItMjFUMjA6NDE6MDEuMzg1WiIgeG1sbnM6c2FtbD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4wOmFzc2VydGlvbiI%2BPHNhbWw6Q29uZGl0aW9ucyBOb3RCZWZvcmU9IjIwMjQtMDItMjFUMjA6NDE6MDEuMDI2WiIgTm90T25PckFmdGVyPSIyMDI0LTAyLTIxVDIxOjQxOjAxLjAyNloiPjxzYW1sOkF1ZGllbmNlUmVzdHJpY3Rpb25Db25kaXRpb24%2BPHNhbWw6QXVkaWVuY2U%2BdXJuOmZlZGVyYXRpb246TWljcm9zb2Z0T25saW5lPC9zYW1sOkF1ZGllbmNlPjwvc2FtbDpBdWRpZW5jZVJlc3RyaWN0aW9uQ29uZGl0aW9uPjwvc2FtbDpDb25kaXRpb25zPjxzYW1sOkF0dHJpYnV0ZVN0YXRlbWVudD48c2FtbDpTdWJqZWN0PjxzYW1sOk5hbWVJZGVudGlmaWVyIEZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4xOm5hbWVpZC1mb3JtYXQ6dW5zcGVjaWZpZWQiPjRwR0s0dFRoQ2thbUpxQWozM3NoWkE9PTwvc2FtbDpOYW1lSWRlbnRpZmllcj48c2FtbDpTdWJqZWN0Q29uZmlybWF0aW9uPjxzYW1sOkNvbmZpcm1hdGlvbk1ldGhvZD51cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoxLjA6Y206YmVhcmVyPC9zYW1sOkNvbmZpcm1hdGlvbk1ldGhvZD48L3NhbWw6U3ViamVjdENvbmZpcm1hdGlvbj48L3NhbWw6U3ViamVjdD48c2FtbDpBdHRyaWJ1dGUgQXR0cmlidXRlTmFtZT0iVVBOIiBBdHRyaWJ1dGVOYW1lc3BhY2U9Imh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL2NsYWltcyI%2BPHNhbWw6QXR0cmlidXRlVmFsdWU%2Bazhjb25uZWN0c2FAbWljcm9zb2Z0LmNvbTwvc2FtbDpBdHRyaWJ1dGVWYWx1ZT48L3NhbWw6QXR0cmlidXRlPjxzYW1sOkF0dHJpYnV0ZSBBdHRyaWJ1dGVOYW1lPSJvYmplY3RHVUlEIiBBdHRyaWJ1dGVOYW1lc3BhY2U9Imh0dHA6Ly90ZW1wdXJpLmNvbSI%2BPHNhbWw6QXR0cmlidXRlVmFsdWU%2BNHBHSzR0VGhDa2FtSnFBajMzc2haQT09PC9zYW1sOkF0dHJpYnV0ZVZhbHVlPjwvc2FtbDpBdHRyaWJ1dGU%2BPHNhbWw6QXR0cmlidXRlIEF0dHJpYnV0ZU5hbWU9IlBlcnNvbm5lbE51bWJlciIgQXR0cmlidXRlTmFtZXNwYWNlPSJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy9jbGFpbXMiPjxzYW1sOkF0dHJpYnV0ZVZhbHVlPjRwR0s0dFRoQ2thbUpxQWozM3NoWkE9PTwvc2FtbDpBdHRyaWJ1dGVWYWx1ZT48L3NhbWw6QXR0cmlidXRlPjxzYW1sOkF0dHJpYnV0ZSBBdHRyaWJ1dGVOYW1lPSJJbW11dGFibGVJRCIgQXR0cmlidXRlTmFtZXNwYWNlPSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL0xpdmVJRC9GZWRlcmF0aW9uLzIwMDgvMDUiPjxzYW1sOkF0dHJpYnV0ZVZhbHVlPjRwR0s0dFRoQ2thbUpxQWozM3NoWkE9PTwvc2FtbDpBdHRyaWJ1dGVWYWx1ZT48L3NhbWw6QXR0cmlidXRlPjxzYW1sOkF0dHJpYnV0ZSBBdHRyaWJ1dGVOYW1lPSJhdXRobm1ldGhvZHNyZWZlcmVuY2VzIiBBdHRyaWJ1dGVOYW1lc3BhY2U9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vY2xhaW1zIj48c2FtbDpBdHRyaWJ1dGVWYWx1ZT5odHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvYXV0aGVudGljYXRpb25tZXRob2QvcGFzc3dvcmQ8L3NhbWw6QXR0cmlidXRlVmFsdWU%2BPC9zYW1sOkF0dHJpYnV0ZT48c2FtbDpBdHRyaWJ1dGUgQXR0cmlidXRlTmFtZT0icGFzc3dvcmRleHBpcmF0aW9udGltZSIgQXR0cmlidXRlTmFtZXNwYWNlPSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMTIvMDEiPjxzYW1sOkF0dHJpYnV0ZVZhbHVlPjIwMjQtMDktMjFUMjE6MDA6MDMuNzU3Wjwvc2FtbDpBdHRyaWJ1dGVWYWx1ZT48L3NhbWw6QXR0cmlidXRlPjxzYW1sOkF0dHJpYnV0ZSBBdHRyaWJ1dGVOYW1lPSJwYXNzd29yZGNoYW5nZXVybCIgQXR0cmlidXRlTmFtZXNwYWNlPSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMTIvMDEiPjxzYW1sOkF0dHJpYnV0ZVZhbHVlPmh0dHBzOi8vc3NwbS5taWNyb3NvZnQuY29tPC9zYW1sOkF0dHJpYnV0ZVZhbHVlPjwvc2FtbDpBdHRyaWJ1dGU%2BPHNhbWw6QXR0cmlidXRlIEF0dHJpYnV0ZU5hbWU9ImNsaWVudC1yZXF1ZXN0LWlkIiBBdHRyaWJ1dGVOYW1lc3BhY2U9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vMjAxMi8wMS9yZXF1ZXN0Y29udGV4dC9jbGFpbXMiIGE6T3JpZ2luYWxJc3N1ZXI9IkNMSUVOVCBDT05URVhUIiB4bWxuczphPSJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA5LzA5L2lkZW50aXR5L2NsYWltcyI%2BPHNhbWw6QXR0cmlidXRlVmFsdWU%2BNDMzMzIzZWQtM2VkZi00MTliLWJmNTEtNzZiN2EwM2JjZTQ3PC9zYW1sOkF0dHJpYnV0ZVZhbHVlPjwvc2FtbDpBdHRyaWJ1dGU%2BPC9zYW1sOkF0dHJpYnV0ZVN0YXRlbWVudD48c2FtbDpBdXRoZW50aWNhdGlvblN0YXRlbWVudCBBdXRoZW50aWNhdGlvbk1ldGhvZD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4wOmFtOnBhc3N3b3JkIiBBdXRoZW50aWNhdGlvbkluc3RhbnQ9IjIwMjQtMDItMjFUMjA6NDE6MDAuODcwWiI%2BPHNhbWw6U3ViamVjdD48c2FtbDpOYW1lSWRlbnRpZmllciBGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjEuMTpuYW1laWQtZm9ybWF0OnVuc3BlY2lmaWVkIj40cEdLNHRUaENrYW1KcUFqMzNzaFpBPT08L3NhbWw6TmFtZUlkZW50aWZpZXI%2BPHNhbWw6U3ViamVjdENvbmZpcm1hdGlvbj48c2FtbDpDb25maXJtYXRpb25NZXRob2Q%2BdXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4wOmNtOmJlYXJlcjwvc2FtbDpDb25maXJtYXRpb25NZXRob2Q%2BPC9zYW1sOlN1YmplY3RDb25maXJtYXRpb24%2BPC9zYW1sOlN1YmplY3Q%2BPC9zYW1sOkF1dGhlbnRpY2F0aW9uU3RhdGVtZW50PjxkczpTaWduYXR1cmUgeG1sbnM6ZHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiPjxkczpTaWduZWRJbmZvPjxkczpDYW5vbmljYWxpemF0aW9uTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIi8%2BPGRzOlNpZ25hdHVyZU1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZHNpZy1tb3JlI3JzYS1zaGEyNTYiLz48ZHM6UmVmZXJlbmNlIFVSST0iI19jODZlMDExYS04OTU2LTRkNjEtYWMyNC0xMjg2NDk5NzNjNjQiPjxkczpUcmFuc2Zvcm1zPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjZW52ZWxvcGVkLXNpZ25hdHVyZSIvPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiLz48L2RzOlRyYW5zZm9ybXM%2BPGRzOkRpZ2VzdE1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jI3NoYTI1NiIvPjxkczpEaWdlc3RWYWx1ZT5IOUVGTGt1UTVjaTJadWJod2hObGEwODVyZGdBYzFYY0QweTBiYzhnekVzPTwvZHM6RGlnZXN0VmFsdWU%2BPC9kczpSZWZlcmVuY2U%2BPC9kczpTaWduZWRJbmZvPjxkczpTaWduYXR1cmVWYWx1ZT5DRDErbG1FVyt5R0NBaG14NDRWNURaQzVvVEFXWHZ4dTdoT2ZPZUVwbWM3WHo0bnQ5U09lQUtiNUhMaFFwdUNKREphUzJPZkVHSU5NMXFLd0dSNFNScnRVeFBveXB1SE0xb09GOGdTaTRRR3hDR1h6aHk3eEw0NXRZc3JjTit5R3FDTXJ0OGdsOFllZUJyNlpFSG9wTjE5RWFwbGdXN2VuQUFOZmVuU2lxOXZ0UjJodDJDcjN0UG9GTC95bGlmbGFIMFdpZUlQaU9FQXBYM1lXeWQ4Vy95ejBDRFdqWFUwamJsUmI1c3V2SDU0MXM3Um9GL2QwRFQ2dGFRZ2hVdHUrYzQ2VC9pYXFYb1lHemxxUGx4M2dLYmQ2M05zTVVTSUorSFp5Wi9rMm10eFB0ak04ZjF1UGFjd1crQUdlVUt4bmpjT2k4V0lzd1hST0tvRzY3emtvRmc9PTwvZHM6U2lnbmF0dXJlVmFsdWU%2BPEtleUluZm8geG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiPjxYNTA5RGF0YT48WDUwOUNlcnRpZmljYXRlPk1JSUljRENDQmxpZ0F3SUJBZ0lUTXdBaEtnTENqclVNeDJsaWh3QUFBQ0VxQWpBTkJna3Foa2lHOXcwQkFRd0ZBREJkTVFzd0NRWURWUVFHRXdKVlV6RWVNQndHQTFVRUNoTVZUV2xqY205emIyWjBJRU52Y25CdmNtRjBhVzl1TVM0d0xBWURWUVFERXlWTmFXTnliM052Wm5RZ1FYcDFjbVVnVWxOQklGUk1VeUJKYzNOMWFXNW5JRU5CSURBME1CNFhEVEkwTURFeE5qRTRNVFF5TlZvWERUSTFNREV4TURFNE1UUXlOVm93YlRFTE1Ba0dBMVVFQmhNQ1ZWTXhDekFKQmdOVkJBZ1RBbGRCTVJBd0RnWURWUVFIRXdkU1pXUnRiMjVrTVI0d0hBWURWUVFLRXhWTmFXTnliM052Wm5RZ1EyOXljRzl5WVhScGIyNHhIekFkQmdOVkJBTVRGbTF6Wm5RdWMzUnpMbTFwWTNKdmMyOW1kQzVqYjIwd2dnRWlNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJEd0F3Z2dFS0FvSUJBUURGS2xzVkdYVjlKRk9kVUpPcDQ5emJjSTFVdHl3TUZwNFZyN0RWRFlqemxFazhnRjh3VUpGaHFPYzU2b1pVMGpLQm9BV2tDMHNlZnBmWG1kYXpiN1lzQ0ZqcFVaL3BXZWwwaU5zbURIaUFsK3l0ZnloeWkrQm5rQ0pDckNUSmlhSzJWTnAwUWdZSEpsNktwcFZZRld1QXIzVVZoeUd0Q3hjb1pydVlMQmxiN1VOMlQ2QWJSM2E2V0toRDU4UlJBRGE0RWJlY0NvbjZNdFZ2OUFlUWRpK2l6SzdoaElHZWc1Q1BNdUlFTzAyZCtLZ0FyTGxYQURtM0pPNWllL0p0bm9QU01zQ0FoSlFHcUt4amEyOElsSjRWb3JNalR1VjVsNzB4N1ZVVkJnMkVJZ3ArdmdKOEY1MUtYUGJRS3VKdnlYU0NMRWwrZmY3dFBqRmhpMmkzZ0UvSkFnTUJBQUdqZ2dRWE1JSUVFekNDQVgwR0Npc0dBUVFCMW5rQ0JBSUVnZ0Z0QklJQmFRRm5BSFVBVG5XakoxeWFFTU00VzJ6VTN6OVM2eDN3NEk0YmpXbkFzZnBrc1dLYU9kOEFBQUdORTRTRzFnQUFCQU1BUmpCRUFpQXFYRzNVdFNibGkzZVlVSWxOazhTSVFZVTVKZHhRa2N6b25Pa2FwK2MzT2dJZ01ZMnBaR0JncjdXZEFRQTUwREJUaDhVN09pUTNkUHZtMUorVEp0Vmh4VW9BZGdCOVdSNFM0WGdxZXh4aFozeGUvZmpRaDF3VW9FNlZucmtETDlrT2pDNTV1QUFBQVkwVGhJYXNBQUFFQXdCSE1FVUNJRXJpV0V0Y0tJekNtbTgzTFpLOW03cUg3VXBxVXk4UU1Ld1p0Ty82Mmk2c0FpRUFnNzBBVXNHaE5QYXJBLzVnUE9rTnBNYVd2SWxiN0xqNDlYSXdEUFdyN1ZFQWRnQlZnZFRDRnBBMkFVcnFDNXRYUEZQd3dPUTRlSEFsQ0Jjdm82b2RCeFBUREFBQUFZMFRoSWluQUFBRUF3QkhNRVVDSVFEWEltb0RJaWRIOXBxdFpWcmtQWGJ6MnBhakttaFZ0bEpGOXpPRDhmN0hYZ0lnYVlYOVhjbW5QU3FtajZBZDBqK25CMWYxS0dhb3Uzd2IrQUhJZkE0ZXpBRXdKd1lKS3dZQkJBR0NOeFVLQkJvd0dEQUtCZ2dyQmdFRkJRY0RBakFLQmdnckJnRUZCUWNEQVRBOEJna3JCZ0VFQVlJM0ZRY0VMekF0QmlVckJnRUVBWUkzRlFpSHZkY2JnZWZyUm9LQm5TNk8wQXlIOE5vZFhZS0U1V21DODZjK0FnRmtBZ0VtTUlHMEJnZ3JCZ0VGQlFjQkFRU0JwekNCcERCekJnZ3JCZ0VGQlFjd0FvWm5hSFIwY0RvdkwzZDNkeTV0YVdOeWIzTnZablF1WTI5dEwzQnJhVzl3Y3k5alpYSjBjeTlOYVdOeWIzTnZablFsTWpCQmVuVnlaU1V5TUZKVFFTVXlNRlJNVXlVeU1FbHpjM1ZwYm1jbE1qQkRRU1V5TURBMEpUSXdMU1V5TUhoemFXZHVMbU55ZERBdEJnZ3JCZ0VGQlFjd0FZWWhhSFIwY0RvdkwyOXVaVzlqYzNBdWJXbGpjbTl6YjJaMExtTnZiUzl2WTNOd01CMEdBMVVkRGdRV0JCUVdzdG4vTkhNdzhCMDJzZ0xOY0FMWnhLTU5NVEFPQmdOVkhROEJBZjhFQkFNQ0JhQXdJUVlEVlIwUkJCb3dHSUlXYlhObWRDNXpkSE11YldsamNtOXpiMlowTG1OdmJUQU1CZ05WSFJNQkFmOEVBakFBTUdvR0ExVWRId1JqTUdFd1g2QmRvRnVHV1doMGRIQTZMeTkzZDNjdWJXbGpjbTl6YjJaMExtTnZiUzl3YTJsdmNITXZZM0pzTDAxcFkzSnZjMjltZENVeU1FRjZkWEpsSlRJd1VsTkJKVEl3VkV4VEpUSXdTWE56ZFdsdVp5VXlNRU5CSlRJd01EUXVZM0pzTUdZR0ExVWRJQVJmTUYwd1VRWU1Ld1lCQkFHQ04weURmUUVCTUVFd1B3WUlLd1lCQlFVSEFnRVdNMmgwZEhBNkx5OTNkM2N1YldsamNtOXpiMlowTG1OdmJTOXdhMmx2Y0hNdlJHOWpjeTlTWlhCdmMybDBiM0o1TG1oMGJUQUlCZ1puZ1F3QkFnSXdId1lEVlIwakJCZ3dGb0FVTzNEUlUrbDJKWjFncU1wbUQ4YWJybTlVRm1vd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3SUdDQ3NHQVFVRkJ3TUJNQTBHQ1NxR1NJYjNEUUVCREFVQUE0SUNBUUFFMjlNWDF2WWRXU2xKV3Q4UGlydDhXVGdJanVLSkFmMW9yTE9vM1NQMjdtbHJiNlByQWZtVExYN1VTOG5taVc2bVpGMjl4Vzhnb3ZmWkJNczZ3MFh4d2o3Wjl3RlA2aDhYQ1MvMzh2UkhQZkVTMFBnVkhpUTRYNU41Z0R2azlRQVNXU3RuVzhqVWhaLzFmQ0l3c0Y2dFQ3UnJkM1M3OWFVRjhGRVdWL3M1U0tFM2d1N1BrVzkxQlQ0NG5GcTF6ejNjaWw1Qjc2OEQ0TTBJcDlkY3VaK3RlamtiUGtXVndGaHY2dmx3V3lTeXJ1SUlaNU1lRHpoYUpEaFZqSEQ3V2lGMys2aVVoRUl3T05FM0poVVNSTDF0UjZpZmJGeGhKd1R4b1FtNkxMN21DY3FkRkdGZnNoUlF4OTcxN3RQcFIwbEdWZ3FuWXhsQnd2MmxTZ3pobCttV2p5NEM4dHpnS3RoZ05CaFk1bjdSbWw1RkFqZkE2Y1VQUWg2MHdzMzBBZFNhS0RaOGtWTTFxTEtVb0FkNWhqQi9ad0hGTkZvWVFncjFiZ1Rjc3lsdzRBKzN3dUpPNmYvcjRmWnVvaDNUSmppbDI5MFhGZ3ZwNzZvTGVNeFg3em9uVzNIU2IvY05UZUZMTmVGM3NVYnVRUzBoeE16d25qNmpqSXpGSnhhczU0SlpycGtydjJYcHR6RHZiZWVnM29OQVJHdEc0TkY0TkFmYVRWL2M0QXJHeHRnUWw0V3hlYlU1VXo5UnY5V2tmbEo0bkFpL0RreC85ZGJuUWk3VmtUN2ZCdDBidnI5SGFiNkdmWjYyR3RsRWc2ZWlaNWI4WmlOSFBiMzVIV0tYS0RObnBXb2ljWCtsbVdqZkdBWXRkY1M2NERYM2dtVzN4c28vN1dlNkVLUjNidz09PC9YNTA5Q2VydGlmaWNhdGU%2BPC9YNTA5RGF0YT48L0tleUluZm8%2BPC9kczpTaWduYXR1cmU%2BPC9zYW1sOkFzc2VydGlvbj4%3D&client_id=[REDACTED]&client_info=1&grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Asaml1_1-bearer&password=[REDACTED]&req_cnf=[REDACTED]&scope=6256c85f-0aad-4d50-b960-e6e9b21efe35%2F.default+openid+offline_access+profile&token_type=pop&username=USERNAME + form: + assertion: + - PHNhbWw6QXNzZXJ0aW9uIE1ham9yVmVyc2lvbj0iMSIgTWlub3JWZXJzaW9uPSIxIiBBc3NlcnRpb25JRD0iX2M4NmUwMTFhLTg5NTYtNGQ2MS1hYzI0LTEyODY0OTk3M2M2NCIgSXNzdWVyPSJ1cm46ZmVkZXJhdGlvbjpNU0ZUIiBJc3N1ZUluc3RhbnQ9IjIwMjQtMDItMjFUMjA6NDE6MDEuMzg1WiIgeG1sbnM6c2FtbD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4wOmFzc2VydGlvbiI+PHNhbWw6Q29uZGl0aW9ucyBOb3RCZWZvcmU9IjIwMjQtMDItMjFUMjA6NDE6MDEuMDI2WiIgTm90T25PckFmdGVyPSIyMDI0LTAyLTIxVDIxOjQxOjAxLjAyNloiPjxzYW1sOkF1ZGllbmNlUmVzdHJpY3Rpb25Db25kaXRpb24+PHNhbWw6QXVkaWVuY2U+dXJuOmZlZGVyYXRpb246TWljcm9zb2Z0T25saW5lPC9zYW1sOkF1ZGllbmNlPjwvc2FtbDpBdWRpZW5jZVJlc3RyaWN0aW9uQ29uZGl0aW9uPjwvc2FtbDpDb25kaXRpb25zPjxzYW1sOkF0dHJpYnV0ZVN0YXRlbWVudD48c2FtbDpTdWJqZWN0PjxzYW1sOk5hbWVJZGVudGlmaWVyIEZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4xOm5hbWVpZC1mb3JtYXQ6dW5zcGVjaWZpZWQiPjRwR0s0dFRoQ2thbUpxQWozM3NoWkE9PTwvc2FtbDpOYW1lSWRlbnRpZmllcj48c2FtbDpTdWJqZWN0Q29uZmlybWF0aW9uPjxzYW1sOkNvbmZpcm1hdGlvbk1ldGhvZD51cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoxLjA6Y206YmVhcmVyPC9zYW1sOkNvbmZpcm1hdGlvbk1ldGhvZD48L3NhbWw6U3ViamVjdENvbmZpcm1hdGlvbj48L3NhbWw6U3ViamVjdD48c2FtbDpBdHRyaWJ1dGUgQXR0cmlidXRlTmFtZT0iVVBOIiBBdHRyaWJ1dGVOYW1lc3BhY2U9Imh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL2NsYWltcyI+PHNhbWw6QXR0cmlidXRlVmFsdWU+azhjb25uZWN0c2FAbWljcm9zb2Z0LmNvbTwvc2FtbDpBdHRyaWJ1dGVWYWx1ZT48L3NhbWw6QXR0cmlidXRlPjxzYW1sOkF0dHJpYnV0ZSBBdHRyaWJ1dGVOYW1lPSJvYmplY3RHVUlEIiBBdHRyaWJ1dGVOYW1lc3BhY2U9Imh0dHA6Ly90ZW1wdXJpLmNvbSI+PHNhbWw6QXR0cmlidXRlVmFsdWU+NHBHSzR0VGhDa2FtSnFBajMzc2haQT09PC9zYW1sOkF0dHJpYnV0ZVZhbHVlPjwvc2FtbDpBdHRyaWJ1dGU+PHNhbWw6QXR0cmlidXRlIEF0dHJpYnV0ZU5hbWU9IlBlcnNvbm5lbE51bWJlciIgQXR0cmlidXRlTmFtZXNwYWNlPSJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy9jbGFpbXMiPjxzYW1sOkF0dHJpYnV0ZVZhbHVlPjRwR0s0dFRoQ2thbUpxQWozM3NoWkE9PTwvc2FtbDpBdHRyaWJ1dGVWYWx1ZT48L3NhbWw6QXR0cmlidXRlPjxzYW1sOkF0dHJpYnV0ZSBBdHRyaWJ1dGVOYW1lPSJJbW11dGFibGVJRCIgQXR0cmlidXRlTmFtZXNwYWNlPSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL0xpdmVJRC9GZWRlcmF0aW9uLzIwMDgvMDUiPjxzYW1sOkF0dHJpYnV0ZVZhbHVlPjRwR0s0dFRoQ2thbUpxQWozM3NoWkE9PTwvc2FtbDpBdHRyaWJ1dGVWYWx1ZT48L3NhbWw6QXR0cmlidXRlPjxzYW1sOkF0dHJpYnV0ZSBBdHRyaWJ1dGVOYW1lPSJhdXRobm1ldGhvZHNyZWZlcmVuY2VzIiBBdHRyaWJ1dGVOYW1lc3BhY2U9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vY2xhaW1zIj48c2FtbDpBdHRyaWJ1dGVWYWx1ZT5odHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvYXV0aGVudGljYXRpb25tZXRob2QvcGFzc3dvcmQ8L3NhbWw6QXR0cmlidXRlVmFsdWU+PC9zYW1sOkF0dHJpYnV0ZT48c2FtbDpBdHRyaWJ1dGUgQXR0cmlidXRlTmFtZT0icGFzc3dvcmRleHBpcmF0aW9udGltZSIgQXR0cmlidXRlTmFtZXNwYWNlPSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMTIvMDEiPjxzYW1sOkF0dHJpYnV0ZVZhbHVlPjIwMjQtMDktMjFUMjE6MDA6MDMuNzU3Wjwvc2FtbDpBdHRyaWJ1dGVWYWx1ZT48L3NhbWw6QXR0cmlidXRlPjxzYW1sOkF0dHJpYnV0ZSBBdHRyaWJ1dGVOYW1lPSJwYXNzd29yZGNoYW5nZXVybCIgQXR0cmlidXRlTmFtZXNwYWNlPSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMTIvMDEiPjxzYW1sOkF0dHJpYnV0ZVZhbHVlPmh0dHBzOi8vc3NwbS5taWNyb3NvZnQuY29tPC9zYW1sOkF0dHJpYnV0ZVZhbHVlPjwvc2FtbDpBdHRyaWJ1dGU+PHNhbWw6QXR0cmlidXRlIEF0dHJpYnV0ZU5hbWU9ImNsaWVudC1yZXF1ZXN0LWlkIiBBdHRyaWJ1dGVOYW1lc3BhY2U9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vMjAxMi8wMS9yZXF1ZXN0Y29udGV4dC9jbGFpbXMiIGE6T3JpZ2luYWxJc3N1ZXI9IkNMSUVOVCBDT05URVhUIiB4bWxuczphPSJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA5LzA5L2lkZW50aXR5L2NsYWltcyI+PHNhbWw6QXR0cmlidXRlVmFsdWU+NDMzMzIzZWQtM2VkZi00MTliLWJmNTEtNzZiN2EwM2JjZTQ3PC9zYW1sOkF0dHJpYnV0ZVZhbHVlPjwvc2FtbDpBdHRyaWJ1dGU+PC9zYW1sOkF0dHJpYnV0ZVN0YXRlbWVudD48c2FtbDpBdXRoZW50aWNhdGlvblN0YXRlbWVudCBBdXRoZW50aWNhdGlvbk1ldGhvZD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4wOmFtOnBhc3N3b3JkIiBBdXRoZW50aWNhdGlvbkluc3RhbnQ9IjIwMjQtMDItMjFUMjA6NDE6MDAuODcwWiI+PHNhbWw6U3ViamVjdD48c2FtbDpOYW1lSWRlbnRpZmllciBGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjEuMTpuYW1laWQtZm9ybWF0OnVuc3BlY2lmaWVkIj40cEdLNHRUaENrYW1KcUFqMzNzaFpBPT08L3NhbWw6TmFtZUlkZW50aWZpZXI+PHNhbWw6U3ViamVjdENvbmZpcm1hdGlvbj48c2FtbDpDb25maXJtYXRpb25NZXRob2Q+dXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4wOmNtOmJlYXJlcjwvc2FtbDpDb25maXJtYXRpb25NZXRob2Q+PC9zYW1sOlN1YmplY3RDb25maXJtYXRpb24+PC9zYW1sOlN1YmplY3Q+PC9zYW1sOkF1dGhlbnRpY2F0aW9uU3RhdGVtZW50PjxkczpTaWduYXR1cmUgeG1sbnM6ZHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiPjxkczpTaWduZWRJbmZvPjxkczpDYW5vbmljYWxpemF0aW9uTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIi8+PGRzOlNpZ25hdHVyZU1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZHNpZy1tb3JlI3JzYS1zaGEyNTYiLz48ZHM6UmVmZXJlbmNlIFVSST0iI19jODZlMDExYS04OTU2LTRkNjEtYWMyNC0xMjg2NDk5NzNjNjQiPjxkczpUcmFuc2Zvcm1zPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjZW52ZWxvcGVkLXNpZ25hdHVyZSIvPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiLz48L2RzOlRyYW5zZm9ybXM+PGRzOkRpZ2VzdE1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jI3NoYTI1NiIvPjxkczpEaWdlc3RWYWx1ZT5IOUVGTGt1UTVjaTJadWJod2hObGEwODVyZGdBYzFYY0QweTBiYzhnekVzPTwvZHM6RGlnZXN0VmFsdWU+PC9kczpSZWZlcmVuY2U+PC9kczpTaWduZWRJbmZvPjxkczpTaWduYXR1cmVWYWx1ZT5DRDErbG1FVyt5R0NBaG14NDRWNURaQzVvVEFXWHZ4dTdoT2ZPZUVwbWM3WHo0bnQ5U09lQUtiNUhMaFFwdUNKREphUzJPZkVHSU5NMXFLd0dSNFNScnRVeFBveXB1SE0xb09GOGdTaTRRR3hDR1h6aHk3eEw0NXRZc3JjTit5R3FDTXJ0OGdsOFllZUJyNlpFSG9wTjE5RWFwbGdXN2VuQUFOZmVuU2lxOXZ0UjJodDJDcjN0UG9GTC95bGlmbGFIMFdpZUlQaU9FQXBYM1lXeWQ4Vy95ejBDRFdqWFUwamJsUmI1c3V2SDU0MXM3Um9GL2QwRFQ2dGFRZ2hVdHUrYzQ2VC9pYXFYb1lHemxxUGx4M2dLYmQ2M05zTVVTSUorSFp5Wi9rMm10eFB0ak04ZjF1UGFjd1crQUdlVUt4bmpjT2k4V0lzd1hST0tvRzY3emtvRmc9PTwvZHM6U2lnbmF0dXJlVmFsdWU+PEtleUluZm8geG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiPjxYNTA5RGF0YT48WDUwOUNlcnRpZmljYXRlPk1JSUljRENDQmxpZ0F3SUJBZ0lUTXdBaEtnTENqclVNeDJsaWh3QUFBQ0VxQWpBTkJna3Foa2lHOXcwQkFRd0ZBREJkTVFzd0NRWURWUVFHRXdKVlV6RWVNQndHQTFVRUNoTVZUV2xqY205emIyWjBJRU52Y25CdmNtRjBhVzl1TVM0d0xBWURWUVFERXlWTmFXTnliM052Wm5RZ1FYcDFjbVVnVWxOQklGUk1VeUJKYzNOMWFXNW5JRU5CSURBME1CNFhEVEkwTURFeE5qRTRNVFF5TlZvWERUSTFNREV4TURFNE1UUXlOVm93YlRFTE1Ba0dBMVVFQmhNQ1ZWTXhDekFKQmdOVkJBZ1RBbGRCTVJBd0RnWURWUVFIRXdkU1pXUnRiMjVrTVI0d0hBWURWUVFLRXhWTmFXTnliM052Wm5RZ1EyOXljRzl5WVhScGIyNHhIekFkQmdOVkJBTVRGbTF6Wm5RdWMzUnpMbTFwWTNKdmMyOW1kQzVqYjIwd2dnRWlNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJEd0F3Z2dFS0FvSUJBUURGS2xzVkdYVjlKRk9kVUpPcDQ5emJjSTFVdHl3TUZwNFZyN0RWRFlqemxFazhnRjh3VUpGaHFPYzU2b1pVMGpLQm9BV2tDMHNlZnBmWG1kYXpiN1lzQ0ZqcFVaL3BXZWwwaU5zbURIaUFsK3l0ZnloeWkrQm5rQ0pDckNUSmlhSzJWTnAwUWdZSEpsNktwcFZZRld1QXIzVVZoeUd0Q3hjb1pydVlMQmxiN1VOMlQ2QWJSM2E2V0toRDU4UlJBRGE0RWJlY0NvbjZNdFZ2OUFlUWRpK2l6SzdoaElHZWc1Q1BNdUlFTzAyZCtLZ0FyTGxYQURtM0pPNWllL0p0bm9QU01zQ0FoSlFHcUt4amEyOElsSjRWb3JNalR1VjVsNzB4N1ZVVkJnMkVJZ3ArdmdKOEY1MUtYUGJRS3VKdnlYU0NMRWwrZmY3dFBqRmhpMmkzZ0UvSkFnTUJBQUdqZ2dRWE1JSUVFekNDQVgwR0Npc0dBUVFCMW5rQ0JBSUVnZ0Z0QklJQmFRRm5BSFVBVG5XakoxeWFFTU00VzJ6VTN6OVM2eDN3NEk0YmpXbkFzZnBrc1dLYU9kOEFBQUdORTRTRzFnQUFCQU1BUmpCRUFpQXFYRzNVdFNibGkzZVlVSWxOazhTSVFZVTVKZHhRa2N6b25Pa2FwK2MzT2dJZ01ZMnBaR0JncjdXZEFRQTUwREJUaDhVN09pUTNkUHZtMUorVEp0Vmh4VW9BZGdCOVdSNFM0WGdxZXh4aFozeGUvZmpRaDF3VW9FNlZucmtETDlrT2pDNTV1QUFBQVkwVGhJYXNBQUFFQXdCSE1FVUNJRXJpV0V0Y0tJekNtbTgzTFpLOW03cUg3VXBxVXk4UU1Ld1p0Ty82Mmk2c0FpRUFnNzBBVXNHaE5QYXJBLzVnUE9rTnBNYVd2SWxiN0xqNDlYSXdEUFdyN1ZFQWRnQlZnZFRDRnBBMkFVcnFDNXRYUEZQd3dPUTRlSEFsQ0Jjdm82b2RCeFBUREFBQUFZMFRoSWluQUFBRUF3QkhNRVVDSVFEWEltb0RJaWRIOXBxdFpWcmtQWGJ6MnBhakttaFZ0bEpGOXpPRDhmN0hYZ0lnYVlYOVhjbW5QU3FtajZBZDBqK25CMWYxS0dhb3Uzd2IrQUhJZkE0ZXpBRXdKd1lKS3dZQkJBR0NOeFVLQkJvd0dEQUtCZ2dyQmdFRkJRY0RBakFLQmdnckJnRUZCUWNEQVRBOEJna3JCZ0VFQVlJM0ZRY0VMekF0QmlVckJnRUVBWUkzRlFpSHZkY2JnZWZyUm9LQm5TNk8wQXlIOE5vZFhZS0U1V21DODZjK0FnRmtBZ0VtTUlHMEJnZ3JCZ0VGQlFjQkFRU0JwekNCcERCekJnZ3JCZ0VGQlFjd0FvWm5hSFIwY0RvdkwzZDNkeTV0YVdOeWIzTnZablF1WTI5dEwzQnJhVzl3Y3k5alpYSjBjeTlOYVdOeWIzTnZablFsTWpCQmVuVnlaU1V5TUZKVFFTVXlNRlJNVXlVeU1FbHpjM1ZwYm1jbE1qQkRRU1V5TURBMEpUSXdMU1V5TUhoemFXZHVMbU55ZERBdEJnZ3JCZ0VGQlFjd0FZWWhhSFIwY0RvdkwyOXVaVzlqYzNBdWJXbGpjbTl6YjJaMExtTnZiUzl2WTNOd01CMEdBMVVkRGdRV0JCUVdzdG4vTkhNdzhCMDJzZ0xOY0FMWnhLTU5NVEFPQmdOVkhROEJBZjhFQkFNQ0JhQXdJUVlEVlIwUkJCb3dHSUlXYlhObWRDNXpkSE11YldsamNtOXpiMlowTG1OdmJUQU1CZ05WSFJNQkFmOEVBakFBTUdvR0ExVWRId1JqTUdFd1g2QmRvRnVHV1doMGRIQTZMeTkzZDNjdWJXbGpjbTl6YjJaMExtTnZiUzl3YTJsdmNITXZZM0pzTDAxcFkzSnZjMjltZENVeU1FRjZkWEpsSlRJd1VsTkJKVEl3VkV4VEpUSXdTWE56ZFdsdVp5VXlNRU5CSlRJd01EUXVZM0pzTUdZR0ExVWRJQVJmTUYwd1VRWU1Ld1lCQkFHQ04weURmUUVCTUVFd1B3WUlLd1lCQlFVSEFnRVdNMmgwZEhBNkx5OTNkM2N1YldsamNtOXpiMlowTG1OdmJTOXdhMmx2Y0hNdlJHOWpjeTlTWlhCdmMybDBiM0o1TG1oMGJUQUlCZ1puZ1F3QkFnSXdId1lEVlIwakJCZ3dGb0FVTzNEUlUrbDJKWjFncU1wbUQ4YWJybTlVRm1vd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3SUdDQ3NHQVFVRkJ3TUJNQTBHQ1NxR1NJYjNEUUVCREFVQUE0SUNBUUFFMjlNWDF2WWRXU2xKV3Q4UGlydDhXVGdJanVLSkFmMW9yTE9vM1NQMjdtbHJiNlByQWZtVExYN1VTOG5taVc2bVpGMjl4Vzhnb3ZmWkJNczZ3MFh4d2o3Wjl3RlA2aDhYQ1MvMzh2UkhQZkVTMFBnVkhpUTRYNU41Z0R2azlRQVNXU3RuVzhqVWhaLzFmQ0l3c0Y2dFQ3UnJkM1M3OWFVRjhGRVdWL3M1U0tFM2d1N1BrVzkxQlQ0NG5GcTF6ejNjaWw1Qjc2OEQ0TTBJcDlkY3VaK3RlamtiUGtXVndGaHY2dmx3V3lTeXJ1SUlaNU1lRHpoYUpEaFZqSEQ3V2lGMys2aVVoRUl3T05FM0poVVNSTDF0UjZpZmJGeGhKd1R4b1FtNkxMN21DY3FkRkdGZnNoUlF4OTcxN3RQcFIwbEdWZ3FuWXhsQnd2MmxTZ3pobCttV2p5NEM4dHpnS3RoZ05CaFk1bjdSbWw1RkFqZkE2Y1VQUWg2MHdzMzBBZFNhS0RaOGtWTTFxTEtVb0FkNWhqQi9ad0hGTkZvWVFncjFiZ1Rjc3lsdzRBKzN3dUpPNmYvcjRmWnVvaDNUSmppbDI5MFhGZ3ZwNzZvTGVNeFg3em9uVzNIU2IvY05UZUZMTmVGM3NVYnVRUzBoeE16d25qNmpqSXpGSnhhczU0SlpycGtydjJYcHR6RHZiZWVnM29OQVJHdEc0TkY0TkFmYVRWL2M0QXJHeHRnUWw0V3hlYlU1VXo5UnY5V2tmbEo0bkFpL0RreC85ZGJuUWk3VmtUN2ZCdDBidnI5SGFiNkdmWjYyR3RsRWc2ZWlaNWI4WmlOSFBiMzVIV0tYS0RObnBXb2ljWCtsbVdqZkdBWXRkY1M2NERYM2dtVzN4c28vN1dlNkVLUjNidz09PC9YNTA5Q2VydGlmaWNhdGU+PC9YNTA5RGF0YT48L0tleUluZm8+PC9kczpTaWduYXR1cmU+PC9zYW1sOkFzc2VydGlvbj4= + client_id: + - '[REDACTED]' + client_info: + - "1" + grant_type: + - urn:ietf:params:oauth:grant-type:saml1_1-bearer + password: + - '[REDACTED]' + req_cnf: + - '[REDACTED]' + scope: + - '[REDACTED]/.default openid offline_access profile' + token_type: + - pop + username: + - USERNAME + headers: + Accept-Encoding: + - gzip + Client-Request-Id: + - 43faea79-1c3f-438b-987d-d79438260519 + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Return-Client-Request-Id: + - "false" + X-Client-Cpu: + - amd64 + X-Client-Os: + - linux + X-Client-Sku: + - MSAL.Go + X-Client-Ver: + - 1.2.0 + url: https://login.microsoftonline.com/AZURE_TENANT_ID/oauth2/v2.0/token + method: POST + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + transfer_encoding: [] + trailer: {} + content_length: 4950 + uncompressed: false + body: '{"token_type":"Bearer","expires_in":86399,"ext_expires_in":86399,"access_token":"TEST_ACCESS_TOKEN"}' + headers: + Cache-Control: + - no-store, no-cache + Client-Request-Id: + - 43faea79-1c3f-438b-987d-d79438260519 + Content-Length: + - "4950" + Content-Type: + - application/json; charset=utf-8 + Date: + - Wed, 21 Feb 2024 20:41:03 GMT + Expires: + - "-1" + P3p: + - CP="DSP CUR OTPi IND OTRi ONL FIN" + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + X-Content-Type-Options: + - nosniff + X-Ms-Clitelem: + - 1,0,0,, + X-Ms-Ests-Server: + - 2.1.17396.6 - SCUS ProdSlices + X-Xss-Protection: + - "0" + status: 200 OK + code: 200 + duration: 486.664311ms