Repository: hashicorp/nomad
File: nomad/acl_endpoint.go (Go)

Code before:
		authMethod.Merge(existingMethod)

		authMethod.Canonicalize()

		if err := authMethod.Validate(
			a.srv.config.ACLTokenMinExpirationTTL,
			a.srv.config.ACLTokenMaxExpirationTTL); err != nil {
			return structs.NewErrRPCCodedf(http.StatusBadRequest, "auth method %d invalid: %v", idx, err)
		}

		// Are we trying to upsert a default auth method? Check if there isn't
		// a default one already.
		if authMethod.Default {
			existingMethodsDefaultMethod, _ := stateSnapshot.GetDefaultACLAuthMethod(nil)
			if existingMethodsDefaultMethod != nil && existingMethodsDefaultMethod.Name != authMethod.Name {
				return structs.NewErrRPCCodedf(
					http.StatusBadRequest,
					"default method already exists: %v", existingMethodsDefaultMethod.Name,
				)
			}
		}

		// if PKCE is not explicitly disabled, enable it.
		if authMethod.Config.OIDCDisablePKCE == nil {
			authMethod.Config.OIDCDisablePKCE = pointer.Of(false)
		}
		// if there is a client assertion, ensure it is valid.
		if authMethod.Config.OIDCClientAssertion.IsSet() {
			_, err := a.oidcClientAssertion(authMethod.Config)
			if err != nil {
				return structs.NewErrRPCCodedf(
					http.StatusBadRequest, "invalid OIDCClientAssertion: %s", err,
				)
			}
		}

		authMethod.SetHash()
	}

	// Update via Raft
	_, index, err := a.srv.raftApply(structs.ACLAuthMethodsUpsertRequestType, args)
	if err != nil {
		return err
	}

	// Populate the response. We do a lookup against the state to pick up the
	// proper create / modify times.
	stateSnapshot, err = a.srv.State().Snapshot()
	if err != nil {
		return err
	}

Review comment (security):
I just noticed that the canonicalize calls in `nomad/structs` don't force `authMethod.Config` to be non-nil. Are we catching that somewhere else?

Code after:
		authMethod.Merge(existingMethod)

		authMethod.Canonicalize()

		if err := authMethod.Validate(
			a.srv.config.ACLTokenMinExpirationTTL,
			a.srv.config.ACLTokenMaxExpirationTTL); err != nil {
			return structs.NewErrRPCCodedf(http.StatusBadRequest, "auth method %d invalid: %v", idx, err)
		}

		// Are we trying to upsert a default auth method? Check if there isn't
		// a default one already.
		if authMethod.Default {
			existingMethodsDefaultMethod, _ := stateSnapshot.GetDefaultACLAuthMethod(nil)
			if existingMethodsDefaultMethod != nil && existingMethodsDefaultMethod.Name != authMethod.Name {
				return structs.NewErrRPCCodedf(
					http.StatusBadRequest,
					"default method already exists: %v", existingMethodsDefaultMethod.Name,
				)
			}
		}

		// if this is a new auth method, and PKCE is not explicitly disabled
		// (by setting Enable=false), then enable it. existing auth methods
		// need it to be enabled explicitly (Enable=True).
		if existingMethod == nil && authMethod.Config.OIDCEnablePKCE == nil {
			authMethod.Config.OIDCEnablePKCE = pointer.Of(true)
		}
		// if there is a client assertion, ensure it is valid.
		if authMethod.Config.OIDCClientAssertion.IsSet() {
			_, err := a.oidcClientAssertion(authMethod.Config)
			if err != nil {
				return structs.NewErrRPCCodedf(
					http.StatusBadRequest, "invalid OIDCClientAssertion: %s", err,
				)
			}
		}

		authMethod.SetHash()
	}

	// Update via Raft
	_, index, err := a.srv.raftApply(structs.ACLAuthMethodsUpsertRequestType, args)
	if err != nil {
		return err
	}

	// Populate the response. We do a lookup against the state to pick up the
	// proper create / modify times.
	stateSnapshot, err = a.srv.State().Snapshot()
	if err != nil {