Rename root, api and sdk module paths (imports, go.mod, go_package, ldflags, build scripts, buf configs) and regenerate protobuf/gateway code with the project's pinned toolchain. Wire identifiers unchanged. api gets a local replace for sdk; root/api/sdk require v0.1.0. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
141 lines
5.7 KiB
Go
141 lines
5.7 KiB
Go
// Copyright IBM Corp. 2020, 2026
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package oidc
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"repo.anhonesthost.net/CyberCoveLLC/threshold/internal/db"
|
|
"repo.anhonesthost.net/CyberCoveLLC/threshold/internal/errors"
|
|
"repo.anhonesthost.net/CyberCoveLLC/threshold/internal/kms"
|
|
"repo.anhonesthost.net/CyberCoveLLC/threshold/internal/oplog"
|
|
)
|
|
|
|
// MakeInactive will transition an OIDC auth method from either the
|
|
// ActivePrivateState or the ActivePublicState to the InactiveState.
|
|
// No options are supported.
|
|
func (r *Repository) MakeInactive(ctx context.Context, authMethodId string, version uint32, _ ...Option) (*AuthMethod, error) {
|
|
const op = "oidc.(Repository).MakeInactive"
|
|
updated, err := r.transitionAuthMethodTo(ctx, authMethodId, InactiveState, version)
|
|
if err != nil {
|
|
return nil, errors.Wrap(ctx, err, op)
|
|
}
|
|
return updated, nil
|
|
}
|
|
|
|
// MakePrivate will transition an OIDC auth method from either the
|
|
// InactiveState or the ActivePublicState to the ActivePrivateState. If
|
|
// transitioning from the InactiveState, the transition will only succeed if
|
|
// the auth method is complete and the oidc.ValidateAuthMethod(...) succeeds.
|
|
// If the WithForce option is provided, oidc.ValidateAuthMethod(...) success
|
|
// is not required.
|
|
func (r *Repository) MakePrivate(ctx context.Context, authMethodId string, version uint32, opt ...Option) (*AuthMethod, error) {
|
|
const op = "oidc.(Repository).MakePrivate"
|
|
updated, err := r.transitionAuthMethodTo(ctx, authMethodId, ActivePrivateState, version, opt...)
|
|
if err != nil {
|
|
return nil, errors.Wrap(ctx, err, op)
|
|
}
|
|
return updated, nil
|
|
}
|
|
|
|
// MakePublic will transition an OIDC auth method from either the
|
|
// InactiveState or the ActivePrivateState to the ActivePublicState. If
|
|
// transitioning from the InactiveState, the transition will only succeed if
|
|
// the auth method is complete and the oidc.ValidateAuthMethod(...) succeeds.
|
|
// If the WithForce option is provided, oidc.ValidateAuthMethod(...) success
|
|
// is not required.
|
|
func (r *Repository) MakePublic(ctx context.Context, authMethodId string, version uint32, opt ...Option) (*AuthMethod, error) {
|
|
const op = "oidc.(Repository).MakePublic"
|
|
updated, err := r.transitionAuthMethodTo(ctx, authMethodId, ActivePublicState, version, opt...)
|
|
if err != nil {
|
|
return nil, errors.Wrap(ctx, err, op)
|
|
}
|
|
return updated, nil
|
|
}
|
|
|
|
func (r *Repository) transitionAuthMethodTo(ctx context.Context, authMethodId string, desiredState AuthMethodState, version uint32, opt ...Option) (*AuthMethod, error) {
|
|
const op = "oidc.(Repository).transitionAuthMethodTo"
|
|
if authMethodId == "" {
|
|
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing auth method id")
|
|
}
|
|
if !validState(string(desiredState)) {
|
|
return nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("%s is not a valid auth method state", desiredState))
|
|
}
|
|
am, err := r.lookupAuthMethod(ctx, authMethodId)
|
|
if err != nil {
|
|
return nil, errors.Wrap(ctx, err, op)
|
|
}
|
|
if am == nil {
|
|
return nil, errors.New(ctx, errors.RecordNotFound, op, fmt.Sprintf("%s auth method not found", authMethodId))
|
|
}
|
|
opts := getOpts(opt...)
|
|
if am.OperationalState == string(desiredState) && am.DisableDiscoveredConfigValidation == opts.withForce {
|
|
return am, nil
|
|
}
|
|
if am.OperationalState == string(InactiveState) {
|
|
if !opts.withForce {
|
|
updatedAm := am.Clone()
|
|
updatedAm.OperationalState = string(desiredState)
|
|
if err := r.ValidateDiscoveryInfo(ctx, WithAuthMethod(updatedAm)); err != nil {
|
|
return nil, errors.Wrap(ctx, err, op)
|
|
}
|
|
}
|
|
if err := am.isComplete(ctx); err != nil {
|
|
return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("unable to transition from %s to %s", InactiveState, desiredState)))
|
|
}
|
|
}
|
|
|
|
oplogWrapper, err := r.kms.GetWrapper(ctx, am.ScopeId, kms.KeyPurposeOplog)
|
|
if err != nil {
|
|
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to get oplog wrapper"))
|
|
}
|
|
|
|
var updatedAm *AuthMethod
|
|
_, err = r.writer.DoTx(
|
|
ctx,
|
|
db.StdRetryCnt,
|
|
db.ExpBackoff{},
|
|
func(reader db.Reader, w db.Writer) error {
|
|
updatedAm = am.Clone()
|
|
updatedAm.OperationalState = string(desiredState)
|
|
updatedAm.DisableDiscoveredConfigValidation = opts.withForce
|
|
dbMask := []string{OperationalStateField, DisableDiscoveredConfigValidationField}
|
|
rowsUpdated, err := w.Update(ctx, updatedAm, dbMask, nil, db.WithOplog(oplogWrapper, updatedAm.oplog(oplog.OpType_OP_TYPE_UPDATE)), db.WithVersion(&version))
|
|
switch {
|
|
case err != nil:
|
|
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to update auth method"))
|
|
case err == nil && rowsUpdated > 1:
|
|
return errors.New(ctx, errors.MultipleRecords, op, fmt.Sprintf("updated auth method and %d rows updated", rowsUpdated))
|
|
case err == nil && rowsUpdated == 0:
|
|
// this is different than how "no rows updated" is handled in
|
|
// the typical update pattern since we are not returning the
|
|
// number of rows updated, we need to raise an error here.
|
|
return errors.New(ctx, errors.RecordNotFound, op, fmt.Sprintf("updated auth method and %d rows updated", rowsUpdated))
|
|
default:
|
|
}
|
|
// we need a new repo, that's using the same reader/writer as this TxHandler
|
|
txRepo := &Repository{
|
|
reader: reader,
|
|
writer: w,
|
|
kms: r.kms,
|
|
// intentionally not setting the defaultLimit, so we'll get all
|
|
// the account ids without a limit
|
|
}
|
|
updatedAm, err = txRepo.lookupAuthMethod(ctx, updatedAm.PublicId)
|
|
if err != nil {
|
|
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to lookup auth method after update"))
|
|
}
|
|
if updatedAm == nil {
|
|
return errors.New(ctx, errors.RecordNotFound, op, "unable to lookup auth method after update")
|
|
}
|
|
return err
|
|
},
|
|
)
|
|
if err != nil {
|
|
return nil, errors.Wrap(ctx, err, op)
|
|
}
|
|
return updatedAm, nil
|
|
}
|