Skip to content

Commit

Permalink
fixes #2474 legacy auth queries missing values
Browse files Browse the repository at this point in the history
- adds OIDC property checks on auth queries
- adds legacy property checks on auth queries
  • Loading branch information
andrewpmartinez committed Oct 15, 2024
1 parent 04faa9e commit 17c4c93
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 17 deletions.
3 changes: 3 additions & 0 deletions controller/internal/routes/current_api_session_api_model.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ func MapApiSessionAuthQueriesToRestEntity(ae *env.AppEnv, rc *response.RequestCo
MinLength: authQuery.MinLength,
Provider: authQuery.Provider,
TypeID: authQuery.TypeID,
ClientID: authQuery.ClientID,
Scopes: authQuery.Scopes,
ID: authQuery.ID,
})
}
}
Expand Down
125 changes: 119 additions & 6 deletions tests/auth_external_jwt_signer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,13 +183,20 @@ func Test_Authenticate_External_Jwt(t *testing.T) {
validJwtSignerCert, validJwtSignerPrivateKey := newSelfSignedCert("valid signer")
validJwtSignerCertPem := nfpem.EncodeToString(validJwtSignerCert)

validJwtSignerAuthUrl := "https://valid.jwt.signer.url.example.com"
validJwtSignerClientId := "valid-client-id"
validJwtSignerScopes := []string{"valid-scope1", "valid-scope2"}

validJwtSigner := &rest_model.ExternalJWTSignerCreate{
CertPem: &validJwtSignerCertPem,
Enabled: B(true),
Name: S("Test JWT Signer - Enabled"),
Kid: S(uuid.NewString()),
Issuer: S("the-very-best-iss"),
Audience: S("the-very-best-aud"),
CertPem: &validJwtSignerCertPem,
Enabled: B(true),
Name: S("Test JWT Signer - Enabled"),
Kid: S(uuid.NewString()),
Issuer: S("the-very-best-iss"),
Audience: S("the-very-best-aud"),
ClientID: &validJwtSignerClientId,
Scopes: validJwtSignerScopes,
ExternalAuthURL: &validJwtSignerAuthUrl,
}

createResponseEnv = &rest_model.CreateEnvelope{}
Expand All @@ -198,6 +205,7 @@ func Test_Authenticate_External_Jwt(t *testing.T) {
ctx.Req.NoError(err)
ctx.Req.Equal(http.StatusCreated, resp.StatusCode())

validSignerUsingInternalId := createResponseEnv.Data.ID
signerIds = append(signerIds, createResponseEnv.Data.ID)

//valid signer w/ external id
Expand Down Expand Up @@ -921,4 +929,109 @@ func Test_Authenticate_External_Jwt(t *testing.T) {
ctx.Req.NotNil(result.Data)
ctx.Req.NotNil(result.Data.Token)
})

t.Run("can authenticate with cert auth and secondary ext-jwt", func(t *testing.T) {
ctx.testContextChanged(t)

//create auth policy, new identity w/ policy, create token for authentication
authPolicyCertExtJwt := &rest_model.AuthPolicyCreate{
Name: ToPtr("createCertJwtAuthPolicy"),
Primary: &rest_model.AuthPolicyPrimary{
Cert: &rest_model.AuthPolicyPrimaryCert{
AllowExpiredCerts: ToPtr(true),
Allowed: ToPtr(true),
},
ExtJWT: &rest_model.AuthPolicyPrimaryExtJWT{
AllowedSigners: []string{},
Allowed: ToPtr(false),
},
Updb: &rest_model.AuthPolicyPrimaryUpdb{
Allowed: ToPtr(false),
LockoutDurationMinutes: ToPtr(int64(0)),
MaxAttempts: ToPtr(int64(3)),
MinPasswordLength: ToPtr(int64(7)),
RequireMixedCase: ToPtr(true),
RequireNumberChar: ToPtr(true),
RequireSpecialChar: ToPtr(true),
},
},
Secondary: &rest_model.AuthPolicySecondary{
RequireExtJWTSigner: ToPtr(validSignerUsingInternalId),
RequireTotp: ToPtr(false),
},
}

createCertJwtAuthPolicy := &rest_model.CreateEnvelope{}
resp, err = ctx.AdminManagementSession.newAuthenticatedRequest().SetResult(createCertJwtAuthPolicy).SetBody(authPolicyCertExtJwt).Post("/auth-policies")
ctx.NoError(err)
ctx.Equal(http.StatusCreated, resp.StatusCode(), string(resp.Body()))
ctx.NotNil(createCertJwtAuthPolicy)
ctx.NotNil(createCertJwtAuthPolicy.Data)
ctx.NotEmpty(createCertJwtAuthPolicy.Data.ID)

newId, certAuth := ctx.AdminManagementSession.requireCreateIdentityOttEnrollment(uuid.NewString(), false)

identityPatch := &rest_model.IdentityPatch{
AuthPolicyID: ToPtr(createCertJwtAuthPolicy.Data.ID),
}

resp, err = ctx.AdminManagementSession.newAuthenticatedRequest().SetBody(identityPatch).Patch("/identities/" + newId)
ctx.NoError(err)
ctx.Equal(http.StatusOK, resp.StatusCode(), string(resp.Body()))

jwtToken := jwt.New(jwt.SigningMethodES256)
jwtToken.Claims = jwt.RegisteredClaims{
Audience: []string{*validJwtSigner.Audience},
ExpiresAt: &jwt.NumericDate{Time: time.Now().Add(2 * time.Hour)},
ID: time.Now().String(),
IssuedAt: &jwt.NumericDate{Time: time.Now()},
Issuer: *validJwtSigner.Issuer,
NotBefore: &jwt.NumericDate{Time: time.Now()},
Subject: newId,
}

jwtToken.Header["kid"] = *validJwtSigner.Kid

jwtStrSigned, err := jwtToken.SignedString(validJwtSignerPrivateKey)
ctx.Req.NoError(err)
ctx.Req.NotEmpty(jwtStrSigned)

t.Run("authenticating with cert and jwt yields 0 auth queries", func(t *testing.T) {
ctx.testContextChanged(t)

result := &rest_model.CurrentAPISessionDetailEnvelope{}

testClient, _, transport := ctx.NewClientComponents(EdgeClientApiPath)

transport.TLSClientConfig.Certificates = certAuth.TLSCertificates()

resp, err := testClient.NewRequest().SetResult(result).SetHeader("Authorization", "Bearer "+jwtStrSigned).Post("/authenticate?method=cert")
ctx.Req.NoError(err)
ctx.Req.Equal(http.StatusOK, resp.StatusCode(), string(resp.Body()))
ctx.Req.Empty(result.Data.AuthQueries)
})

t.Run("authenticating with cert and jwt yields 1 ext-jwt auth query", func(t *testing.T) {
ctx.testContextChanged(t)

result := &rest_model.CurrentAPISessionDetailEnvelope{}

testClient, _, transport := ctx.NewClientComponents(EdgeClientApiPath)

transport.TLSClientConfig.Certificates = certAuth.TLSCertificates()

resp, err := testClient.NewRequest().SetResult(result).Post("/authenticate?method=cert")
ctx.Req.NoError(err)
ctx.Req.Equal(http.StatusOK, resp.StatusCode(), string(resp.Body()))
ctx.Req.Len(result.Data.AuthQueries, 1)

ctx.Req.Equal(rest_model.AuthQueryTypeEXTDashJWT, result.Data.AuthQueries[0].TypeID)
ctx.Req.Equal(validJwtSignerClientId, result.Data.AuthQueries[0].ClientID)
ctx.Req.Equal(validJwtSignerScopes[0], result.Data.AuthQueries[0].Scopes[0])
ctx.Req.Equal(validJwtSignerScopes[1], result.Data.AuthQueries[0].Scopes[1])
ctx.Req.Equal(validJwtSignerAuthUrl, result.Data.AuthQueries[0].HTTPURL)
ctx.Req.Equal(validSignerUsingInternalId, result.Data.AuthQueries[0].ID)

})
})
}
52 changes: 41 additions & 11 deletions tests/auth_oidc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,14 +261,21 @@ func Test_Authenticate_OIDC_Auth(t *testing.T) {
ctx.testContextChanged(t)
jwtSignerCert, _ := newSelfSignedCert("Test Jwt Signer Cert - Auth Policy")

clientId := "test-client-id-99"
scope1 := "test-scope-1-99"
scope2 := "test-scope-2-99"
extAuthUrl := "https://some.auth.url.example.com/auth"
createExtJwtParam := external_jwt_signer.NewCreateExternalJWTSignerParams()
createExtJwtParam.ExternalJWTSigner = &rest_model.ExternalJWTSignerCreate{
CertPem: S(nfpem.EncodeToString(jwtSignerCert)),
Enabled: B(true),
Name: S("Test JWT Signer - Auth Policy"),
Kid: S(uuid.NewString()),
Issuer: S("test-issuer-99"),
Audience: S("test-audience-99"),
CertPem: S(nfpem.EncodeToString(jwtSignerCert)),
Enabled: B(true),
Name: S("Test JWT Signer - Auth Policy"),
Kid: S(uuid.NewString()),
Issuer: S("test-issuer-99"),
Audience: S("test-audience-99"),
ClientID: &clientId,
Scopes: []string{scope1, scope2},
ExternalAuthURL: S(extAuthUrl),
}

extJwtCreateResp, err := managementClient.API.ExternalJWTSigner.CreateExternalJWTSigner(createExtJwtParam, nil)
Expand Down Expand Up @@ -337,7 +344,7 @@ func Test_Authenticate_OIDC_Auth(t *testing.T) {
ctx.Req.NoError(rest_util.WrapErr(err))
ctx.Req.NotNil(createIdentityUpdbAuthenticatorResp)

t.Run("can authenticate via UPDB", func(t *testing.T) {
t.Run("can authenticate via UPDB and see two auth queries", func(t *testing.T) {
ctx.testContextChanged(t)
identityClient := resty.NewWithClient(ctx.NewHttpClient(ctx.NewTransport()))
identityClient.SetRedirectPolicy(resty.DomainCheckRedirectPolicy("127.0.0.1", "localhost"))
Expand All @@ -356,14 +363,37 @@ func Test_Authenticate_OIDC_Auth(t *testing.T) {
ctx.Req.NoError(err)
ctx.Req.Equal(http.StatusOK, resp.StatusCode())

parsedBody := map[string]any{
"authQueries": []*rest_model.AuthQueryDetail{},
type respBody struct {
AuthQueries []*rest_model.AuthQueryDetail `json:"authQueries"`
}

err = json.Unmarshal(resp.Body(), &parsedBody)
parsedBody := &respBody{}

err = json.Unmarshal(resp.Body(), parsedBody)
ctx.Req.NoError(err)

ctx.Req.Len(parsedBody["authQueries"], 2)
ctx.Req.Len(parsedBody.AuthQueries, 2)

extJwtIdx := -1
totpIdx := -1

for i, authQuery := range parsedBody.AuthQueries {
if authQuery.TypeID == rest_model.AuthQueryTypeEXTDashJWT {
extJwtIdx = i
} else if authQuery.TypeID == rest_model.AuthQueryTypeTOTP {
totpIdx = i
} else {
ctx.Req.Failf("unexexpected auth quuery type id encountered: %s", string(authQuery.TypeID))
}
}

ctx.Req.True(extJwtIdx >= 0, "expected extJwtIdx to be set")
ctx.Req.True(totpIdx >= 0, "expected totpIdx to be set")

ctx.Req.Equal(parsedBody.AuthQueries[extJwtIdx].ClientID, clientId)
ctx.Req.Equal(parsedBody.AuthQueries[extJwtIdx].Scopes[0], scope1)
ctx.Req.Equal(parsedBody.AuthQueries[extJwtIdx].Scopes[1], scope2)
ctx.Req.Equal(parsedBody.AuthQueries[extJwtIdx].HTTPURL, extAuthUrl)
})

})
Expand Down

0 comments on commit 17c4c93

Please sign in to comment.