mirror of
https://github.com/openziti/ziti.git
synced 2026-09-10 08:45:41 +00:00
8297a817b7
* fixes #3734 enforce client certificate proof-of-possession for OIDC sessions - adds verifyCertProofOfPossession() in resolveOidcSession() to require TLS client cert matching a z_cfs fingerprint or SPIFFE ID when the OIDC token was issued with cert bindings - adds z_cae (CertAllowExpired) claim from auth policy, propagated through token issuance and refresh - adds TrustCache.VerifyClientCert() with tiered pool matching (first-party roots, trust anchors, third-party) and TTL cache - adds WrapIdentityWithCertValidation() on the router to verify client certs at the TLS level against RDM PublicKeys - adds IsFirstPartyCert() on the router to gate SPIFFE ID matching by checking whether the cert chains to the controller root CA - adds VerifySpiffeId() in common/spiffehlp with SpiffeMatchApiSession, SpiffeMatchIdentity, and SpiffeMatchNone return types - adds SPIFFE IDs to OTT and token enrollment certs (/identity/<id>) - enforces cert expiry by match type: API session certs must be valid, fingerprint-matched certs respect z_cae, legacy sessions skip checks - shallow-copies leaf certs before overriding time fields in all cert verification paths to avoid races on shared x509.Certificate pointers - fixes controllerRootCache setting inited=true before the ctrl channel is available, which permanently cached the failure
552 lines
18 KiB
Go
552 lines
18 KiB
Go
/*
|
|
Copyright NetFoundry Inc.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
https://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package model
|
|
|
|
import (
|
|
"crypto/x509"
|
|
"encoding/base64"
|
|
"encoding/pem"
|
|
"fmt"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/michaelquigley/pfxlog"
|
|
"github.com/openziti/foundation/v2/errorz"
|
|
nfpem "github.com/openziti/foundation/v2/pem"
|
|
"github.com/openziti/ziti/v2/common/cert"
|
|
"github.com/openziti/ziti/v2/controller/apierror"
|
|
"github.com/openziti/ziti/v2/controller/change"
|
|
"github.com/openziti/ziti/v2/controller/db"
|
|
"github.com/openziti/ziti/v2/controller/fields"
|
|
"github.com/openziti/ziti/v2/controller/models"
|
|
)
|
|
|
|
const (
|
|
ClientCertHeader = "X-Client-CertPem"
|
|
EdgeRouterProxyRequest = "X-Edge-Router-Proxy-Request"
|
|
|
|
ZitiAuthenticatorExtendRequested = "ziti-authenticator-extend-requested"
|
|
ZitiAuthenticatorRollKeyRequested = "ziti-authenticator-extend-requested"
|
|
|
|
internalCertAuthenticatorId = "internal"
|
|
)
|
|
|
|
var _ AuthProcessor = &AuthModuleCert{}
|
|
|
|
type AuthModuleCert struct {
|
|
BaseAuthenticator
|
|
}
|
|
|
|
func NewAuthModuleCert(env Env) *AuthModuleCert {
|
|
return &AuthModuleCert{
|
|
BaseAuthenticator: BaseAuthenticator{
|
|
env: env,
|
|
method: db.MethodAuthenticatorCert,
|
|
},
|
|
}
|
|
}
|
|
|
|
func (module *AuthModuleCert) CanHandle(method string) bool {
|
|
return method == module.method
|
|
}
|
|
|
|
// verifyClientCerts will verify a set of x509.Certificates provided by a client during the TLS handshake. It is
|
|
// required, as it is required by the TLS spec, that the first certificate is the client's identity. Any additional
|
|
// certificates may be provided in order to provide intermediate CAs that map back to a known root CA in the `roots`
|
|
// argument. The result is an array of valid chains or an error.
|
|
//
|
|
// Note: this function does not validate expiration times specifically to allow for situations where expired
|
|
// certificates are allowed by authentication policy. Due to the way certificate authentication works, we may
|
|
// not know the authentication policy until after the signing root CA is determined.
|
|
func (module *AuthModuleCert) verifyClientCerts(clientCerts []*x509.Certificate, roots *x509.CertPool) ([][]*x509.Certificate, error) {
|
|
// Shallow-copy the leaf cert so we can override time fields without mutating the original
|
|
// (which may be shared across concurrent HTTP/2 requests on the same TLS connection).
|
|
leafCopy := *clientCerts[0]
|
|
leafCopy.NotBefore = time.Now().Add(-1 * time.Hour)
|
|
leafCopy.NotAfter = time.Now().Add(1 * time.Hour)
|
|
|
|
intermediates := x509.NewCertPool()
|
|
for _, curCert := range clientCerts[1:] {
|
|
intermediates.AddCert(curCert)
|
|
}
|
|
|
|
opts := x509.VerifyOptions{
|
|
Roots: roots,
|
|
Intermediates: intermediates,
|
|
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
|
|
}
|
|
|
|
return leafCopy.Verify(opts)
|
|
}
|
|
|
|
// isCertExpirationValid returns true if the provided certificates validations period is currently valid.
|
|
func (module *AuthModuleCert) isCertExpirationValid(clientCert *x509.Certificate) bool {
|
|
now := time.Now()
|
|
return now.Before(clientCert.NotAfter) && now.After(clientCert.NotBefore)
|
|
}
|
|
|
|
// Process will inspect the provided AuthContext and attempt to verify the client certificates provided during
|
|
// a TLS handshake. Authentication via client certificates follows these steps:
|
|
//
|
|
// 1) obtain client certificates
|
|
// 2) verify client certificates against known CAs
|
|
// 3) link a CA certificate back to a model.Ca if possible
|
|
// 4) obtain the target identity by authenticator (cert fingerprint) or by external id (claims stuffed into a x509.Certificate resolved by model.Ca)
|
|
// 5) verify identity status (disabled)
|
|
// 6) obtain the target identity's auth policy
|
|
// 7) verify according to auth policy
|
|
func (module *AuthModuleCert) Process(context AuthContext) (AuthResult, error) {
|
|
logger := pfxlog.Logger().WithField("authMethod", module.method).WithField("changeContext", context.GetChangeContext().Attributes)
|
|
|
|
bundle := &AuthBundle{}
|
|
|
|
certs, err := module.getClientCerts(context)
|
|
|
|
if err != nil {
|
|
reason := fmt.Sprintf("error obtaining client certificates: %v", err)
|
|
failEvent := module.NewAuthEventFailure(context, bundle, reason)
|
|
module.env.GetEventDispatcher().AcceptAuthenticationEvent(failEvent)
|
|
|
|
logger.WithError(err).Error("error obtaining client certificates")
|
|
return nil, err
|
|
}
|
|
|
|
if len(certs) == 0 {
|
|
reason := "no client certificates found"
|
|
failEvent := module.NewAuthEventFailure(context, bundle, reason)
|
|
module.env.GetEventDispatcher().AcceptAuthenticationEvent(failEvent)
|
|
|
|
logger.Error(reason)
|
|
return nil, apierror.NewInvalidAuth()
|
|
}
|
|
|
|
clientCert := certs[0]
|
|
|
|
trustCache := module.env.GetManagers().Ca.GetTrustCache()
|
|
|
|
trustCache.RLock()
|
|
defer trustCache.RUnlock()
|
|
|
|
var targetThirdPartyCa *Ca
|
|
chains, err := module.verifyClientCerts(certs, trustCache.staticFirstPartyRootPool)
|
|
|
|
if err != nil {
|
|
logger.WithError(err).Error("error verifying client certificate via static root pool, trying other pools")
|
|
}
|
|
|
|
if len(chains) == 0 {
|
|
logger.Debug("certificate validation failed via root only pool, trying other pools")
|
|
chains, err = module.verifyClientCerts(certs, trustCache.staticFirstPartyTrustAnchorPool)
|
|
|
|
if err != nil {
|
|
logger.WithError(err).Error("error verifying client certificate via static trust anchor pool, trying other pools")
|
|
}
|
|
|
|
if len(chains) != 0 {
|
|
//succeeded on augmented trust pool, client didn't supply a chain
|
|
bundle.ImproperClientCertChain = true
|
|
} else {
|
|
logger.Debug("certificate validation failed via root+intermediate pool, trying third party pool")
|
|
chains, err = module.verifyClientCerts(certs, trustCache.thirdPartyTrustAnchorPool)
|
|
|
|
if err == nil {
|
|
targetThirdPartyCa = getCaByChain(trustCache.activeThirdPartyCas, chains, module.env.GetFingerprintGenerator())
|
|
|
|
if len(chains) == 0 {
|
|
logger.Debug("certificate validation failed via third party pool")
|
|
}
|
|
} else {
|
|
logger.WithError(err).Error("error verifying client certificate via third party anchor pool")
|
|
}
|
|
}
|
|
}
|
|
|
|
if len(chains) == 0 {
|
|
reason := "failed to verify client via all pools, no valid roots"
|
|
logger.Error(reason)
|
|
|
|
failEvent := module.NewAuthEventFailure(context, bundle, reason)
|
|
module.env.GetEventDispatcher().AcceptAuthenticationEvent(failEvent)
|
|
|
|
return nil, apierror.NewInvalidAuth()
|
|
}
|
|
|
|
externalId := ""
|
|
if targetThirdPartyCa != nil {
|
|
externalId, err = targetThirdPartyCa.GetExternalId(clientCert)
|
|
if err != nil {
|
|
logger.WithError(err).Error("encountered an error getting externalId from x509.Certificate")
|
|
}
|
|
}
|
|
|
|
var identity *Identity
|
|
var authenticator *Authenticator
|
|
|
|
if externalId != "" {
|
|
logger = logger.WithField("externalId", externalId)
|
|
identity, _ = module.env.GetManagers().Identity.ReadByExternalId(externalId)
|
|
|
|
if identity == nil {
|
|
reason := "failed to find identity by externalId"
|
|
failEvent := module.NewAuthEventFailure(context, bundle, reason)
|
|
module.env.GetEventDispatcher().AcceptAuthenticationEvent(failEvent)
|
|
|
|
logger.Error(reason)
|
|
|
|
return nil, apierror.NewInvalidAuth()
|
|
}
|
|
|
|
authenticator = module.authenticatorExternalId(identity.Id, clientCert)
|
|
|
|
} else {
|
|
fingerprint := module.env.GetFingerprintGenerator().FromCert(clientCert)
|
|
logger = logger.WithField("fingerprint", fingerprint)
|
|
|
|
authenticator, _ = module.env.GetManagers().Authenticator.ReadByFingerprint(fingerprint)
|
|
|
|
if authenticator == nil {
|
|
reason := "failed to find authenticator by fingerprint"
|
|
failEvent := module.NewAuthEventFailure(context, bundle, reason)
|
|
module.env.GetEventDispatcher().AcceptAuthenticationEvent(failEvent)
|
|
|
|
logger.Error(reason)
|
|
|
|
return nil, apierror.NewInvalidAuth()
|
|
}
|
|
|
|
identity, _ = module.env.GetManagers().Identity.Read(authenticator.IdentityId)
|
|
}
|
|
|
|
if identity == nil {
|
|
reason := "failed to find a valid identity for authentication"
|
|
failEvent := module.NewAuthEventFailure(context, bundle, reason)
|
|
module.env.GetEventDispatcher().AcceptAuthenticationEvent(failEvent)
|
|
|
|
logger.Error(reason)
|
|
|
|
return nil, apierror.NewInvalidAuth()
|
|
}
|
|
|
|
logger = logger.WithField("authenticatorId", authenticator.Id).
|
|
WithField("authenticatorMethod", authenticator.Method).
|
|
WithField("identityId", authenticator.IdentityId).
|
|
WithField("authPolicyId", identity.AuthPolicyId)
|
|
|
|
if identity.Disabled {
|
|
until := "forever"
|
|
if identity.DisabledUntil != nil {
|
|
until = identity.DisabledUntil.Format(time.RFC3339)
|
|
}
|
|
|
|
at := "unknown"
|
|
if identity.DisabledAt != nil {
|
|
at = identity.DisabledAt.Format(time.RFC3339)
|
|
}
|
|
reason := fmt.Sprintf("authentication failed, identity is disabled (disabledAt: %s, disabledUntil: %s)", at, until)
|
|
failEvent := module.NewAuthEventFailure(context, bundle, reason)
|
|
module.env.GetEventDispatcher().AcceptAuthenticationEvent(failEvent)
|
|
|
|
logger.WithField("disabledUntil", until).WithField("disabledAt", at).Error(reason)
|
|
|
|
return nil, apierror.NewInvalidAuth()
|
|
}
|
|
|
|
authPolicy, _ := module.env.GetManagers().AuthPolicy.Read(identity.AuthPolicyId)
|
|
|
|
if authPolicy == nil {
|
|
reason := "failed to obtain authPolicy by id"
|
|
failEvent := module.NewAuthEventFailure(context, bundle, reason)
|
|
module.env.GetEventDispatcher().AcceptAuthenticationEvent(failEvent)
|
|
|
|
logger.Error(reason)
|
|
return nil, apierror.NewInvalidAuth()
|
|
}
|
|
|
|
if !authPolicy.Primary.Cert.Allowed {
|
|
reason := "invalid certificate authentication, not allowed by auth policy"
|
|
failEvent := module.NewAuthEventFailure(context, bundle, reason)
|
|
module.env.GetEventDispatcher().AcceptAuthenticationEvent(failEvent)
|
|
|
|
logger.Error(reason)
|
|
|
|
return nil, apierror.NewInvalidAuth()
|
|
}
|
|
|
|
if !authPolicy.Primary.Cert.AllowExpiredCerts {
|
|
if !module.isCertExpirationValid(clientCert) {
|
|
reason := "failed to verify expiration period of client certificate"
|
|
failEvent := module.NewAuthEventFailure(context, bundle, reason)
|
|
module.env.GetEventDispatcher().AcceptAuthenticationEvent(failEvent)
|
|
|
|
logger.Error(reason)
|
|
|
|
return nil, apierror.NewInvalidAuth()
|
|
}
|
|
}
|
|
|
|
if authenticator.Id != internalCertAuthenticatorId {
|
|
certAuth := authenticator.ToCert()
|
|
|
|
if certAuth == nil {
|
|
reason := "failed to convert authenticator to cert auth"
|
|
failEvent := module.NewAuthEventFailure(context, bundle, reason)
|
|
module.env.GetEventDispatcher().AcceptAuthenticationEvent(failEvent)
|
|
|
|
logger.Error(reason)
|
|
|
|
return nil, apierror.NewInvalidAuth()
|
|
}
|
|
|
|
module.ensureAuthenticatorIsUpToDate(certAuth, clientCert, !bundle.ImproperClientCertChain, context.GetChangeContext())
|
|
}
|
|
|
|
return &AuthResultBase{
|
|
identity: identity,
|
|
authenticatorId: authenticator.Id,
|
|
authenticator: authenticator,
|
|
sessionCerts: []*x509.Certificate{clientCert},
|
|
authPolicy: authPolicy,
|
|
env: module.env,
|
|
improperClientCertChain: bundle.ImproperClientCertChain,
|
|
}, nil
|
|
}
|
|
|
|
func (module *AuthModuleCert) isEdgeRouter(clientCert *x509.Certificate) bool {
|
|
|
|
fingerprint := module.env.GetFingerprintGenerator().FromCert(clientCert)
|
|
|
|
router, err := module.env.GetManagers().EdgeRouter.ReadOneByFingerprint(fingerprint)
|
|
|
|
if router != nil {
|
|
return true
|
|
}
|
|
|
|
if err != nil {
|
|
pfxlog.Logger().WithError(err).Errorf("could not read edge router by fingerprint %s", fingerprint)
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// getClientCerts will return the client certificates that should be used to verify the authentication
|
|
// request. The client certificates may be directly provided by the TLS handshake or proxied from a trusted
|
|
// source (i.e. edge routers)
|
|
func (module *AuthModuleCert) getClientCerts(ctx AuthContext) ([]*x509.Certificate, error) {
|
|
peerCerts := ctx.GetCerts()
|
|
|
|
if len(peerCerts) == 0 {
|
|
return nil, nil
|
|
}
|
|
|
|
if proxyHeader := ctx.GetHeaders()[EdgeRouterProxyRequest]; proxyHeader != nil {
|
|
return module.getProxiedClientCerts(ctx)
|
|
}
|
|
|
|
return peerCerts, nil
|
|
}
|
|
|
|
// ensureAuthenticatorIsUpToDate ensures that a client's pem, public print, and root status is stored in `cert` authenticators.
|
|
func (module *AuthModuleCert) ensureAuthenticatorIsUpToDate(authCert *AuthenticatorCert, clientCert *x509.Certificate, verifiedToRoot bool, ctx *change.Context) {
|
|
needsUpdate := false
|
|
|
|
fieldChecker := fields.UpdatedFieldsMap{}
|
|
|
|
if authCert.Pem == "" {
|
|
needsUpdate = true
|
|
certPem := pem.EncodeToMemory(&pem.Block{
|
|
Type: "CERTIFICATE",
|
|
Bytes: clientCert.Raw,
|
|
})
|
|
|
|
authCert.Pem = string(certPem)
|
|
|
|
fieldChecker.AddField(db.FieldAuthenticatorCertPem)
|
|
}
|
|
|
|
if authCert.PublicKeyPrint == "" {
|
|
needsUpdate = true
|
|
authCert.PublicKeyPrint = PublicKeySha256(clientCert)
|
|
|
|
fieldChecker.AddField(db.FieldAuthenticatorCertPublicKeyPrint)
|
|
}
|
|
|
|
if authCert.IsIssuedByNetwork {
|
|
if authCert.LastAuthResolvedToRoot != verifiedToRoot {
|
|
needsUpdate = true
|
|
authCert.LastAuthResolvedToRoot = verifiedToRoot
|
|
|
|
fieldChecker.AddField(db.FieldAuthenticatorCertLastAuthResolvedToRoot)
|
|
}
|
|
}
|
|
|
|
if needsUpdate {
|
|
task := func() {
|
|
if err := module.env.GetManagers().Authenticator.Update(authCert.Authenticator, false, fieldChecker, ctx); err != nil {
|
|
pfxlog.Logger().WithError(err).Errorf("error during cert auth update attempt")
|
|
}
|
|
}
|
|
|
|
if !module.env.GetManagers().Command.backGroundableTask(task) {
|
|
pfxlog.Logger().WithField("authenticatorId", authCert.Authenticator.Id).
|
|
Error("system too busy, unable to queue authenticator for synchronization update")
|
|
}
|
|
}
|
|
}
|
|
|
|
// authenticatorExternalId returns an authenticator that represents a cert based CA authentication that uses
|
|
// `externalId` lookups.
|
|
func (module *AuthModuleCert) authenticatorExternalId(identityId string, clientCert *x509.Certificate) *Authenticator {
|
|
authenticator := &Authenticator{
|
|
BaseEntity: models.BaseEntity{
|
|
Id: internalCertAuthenticatorId,
|
|
CreatedAt: time.Now(),
|
|
UpdatedAt: time.Now(),
|
|
Tags: nil,
|
|
IsSystem: true,
|
|
},
|
|
Method: db.MethodAuthenticatorCertCaExternalId,
|
|
IdentityId: identityId,
|
|
}
|
|
|
|
authenticator.SubType = AuthenticatorCert{
|
|
Authenticator: authenticator,
|
|
Fingerprint: module.env.GetFingerprintGenerator().FromCert(clientCert),
|
|
Pem: nfpem.EncodeToString(clientCert),
|
|
}
|
|
|
|
return authenticator
|
|
}
|
|
|
|
func (module *AuthModuleCert) getProxiedClientCerts(ctx AuthContext) ([]*x509.Certificate, error) {
|
|
peerCerts := ctx.GetCerts()
|
|
|
|
if len(peerCerts) == 0 {
|
|
return nil, apierror.NewInvalidAuth()
|
|
}
|
|
|
|
proxyRaw64 := ""
|
|
|
|
if proxyRaw64Interface := ctx.GetHeaders()[ClientCertHeader]; proxyRaw64Interface != nil {
|
|
proxyRaw64 = proxyRaw64Interface.(string)
|
|
}
|
|
|
|
if proxyRaw64 == "" {
|
|
return nil, apierror.NewInvalidAuth()
|
|
}
|
|
|
|
if !module.isEdgeRouter(peerCerts[0]) {
|
|
return nil, apierror.NewInvalidAuth()
|
|
}
|
|
|
|
proxiedRaw := make([]byte, base64.StdEncoding.DecodedLen(len(proxyRaw64)))
|
|
_, err := base64.StdEncoding.Decode(proxiedRaw, []byte(proxyRaw64))
|
|
|
|
if err != nil {
|
|
return nil, &errorz.ApiError{
|
|
AppCode: apierror.CouldNotDecodeProxiedCertCode,
|
|
Message: apierror.CouldNotDecodeProxiedCertMessage,
|
|
Cause: err,
|
|
Status: http.StatusBadRequest,
|
|
}
|
|
}
|
|
|
|
proxiedCerts, err := x509.ParseCertificates(proxiedRaw)
|
|
|
|
if err != nil {
|
|
return nil, &errorz.ApiError{
|
|
AppCode: apierror.CouldNotParseX509FromDerCode,
|
|
Message: apierror.CouldNotParseX509FromDerMessage,
|
|
Cause: err,
|
|
Status: http.StatusBadRequest,
|
|
}
|
|
}
|
|
|
|
return proxiedCerts, nil
|
|
}
|
|
|
|
func getCaByChain(activeCas map[string]*Ca, chains [][]*x509.Certificate, generator cert.FingerprintGenerator) *Ca {
|
|
for _, chain := range chains {
|
|
for _, curCert := range chain {
|
|
fingerprint := generator.FromCert(curCert)
|
|
|
|
if ca, ok := activeCas[fingerprint]; ok {
|
|
return ca
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func getAuthPolicyByIdentityId(env Env, authMethod string, authenticatorId string, identityId string) (*AuthPolicy, *Identity, error) {
|
|
logger := pfxlog.Logger().
|
|
WithField("authenticatorId", authenticatorId).
|
|
WithField("identityId", identityId).
|
|
WithField("authMethod", authMethod)
|
|
identity, err := env.GetManagers().Identity.Read(identityId)
|
|
|
|
if err != nil {
|
|
logger.WithError(err).Errorf("encountered error during %s auth when looking up authenticator", authMethod)
|
|
return nil, nil, apierror.NewInvalidAuth()
|
|
}
|
|
|
|
if identity == nil {
|
|
logger.Errorf("identity not found by identityId")
|
|
return nil, nil, apierror.NewInvalidAuth()
|
|
}
|
|
|
|
logger = logger.WithField("authPolicyId", identity.AuthPolicyId)
|
|
|
|
authPolicy, err := env.GetManagers().AuthPolicy.Read(identity.AuthPolicyId)
|
|
|
|
if err != nil {
|
|
logger.WithError(err).Errorf("encountered error during %s auth when looking up auth policy", authMethod)
|
|
return nil, nil, apierror.NewInvalidAuth()
|
|
}
|
|
|
|
return authPolicy, identity, nil
|
|
}
|
|
|
|
func getAuthPolicyByExternalId(env Env, authMethod string, authenticatorId string, externalId string) (*AuthPolicy, *Identity, error) {
|
|
logger := pfxlog.Logger().
|
|
WithField("authenticatorId", authenticatorId).
|
|
WithField("externalId", externalId).
|
|
WithField("authMethod", authMethod)
|
|
identity, err := env.GetManagers().Identity.ReadByExternalId(externalId)
|
|
|
|
if err != nil {
|
|
logger.WithError(err).Errorf("encountered error during %s auth when looking up authenticator", authMethod)
|
|
return nil, nil, apierror.NewInvalidAuth()
|
|
}
|
|
|
|
if identity == nil {
|
|
logger.Errorf("identity not found by externalId")
|
|
return nil, nil, apierror.NewInvalidAuth()
|
|
}
|
|
|
|
logger = logger.WithField("authPolicyId", identity.AuthPolicyId)
|
|
|
|
authPolicy, err := env.GetManagers().AuthPolicy.Read(identity.AuthPolicyId)
|
|
|
|
if err != nil {
|
|
logger.WithError(err).Errorf("encountered error during %s auth when looking up auth policy", authMethod)
|
|
return nil, nil, apierror.NewInvalidAuth()
|
|
}
|
|
|
|
return authPolicy, identity, nil
|
|
}
|