hscontrol/oidc: fix ACL policy not applied to new OIDC nodes (#2890)

Fixes #2888
Fixes #2896
This commit is contained in:
Kristoffer Dalby
2025-11-30 19:02:15 +01:00
committed by GitHub
parent 7e8cee6b10
commit 4fe5cbe703
9 changed files with 757 additions and 107 deletions

View File

@@ -42,10 +42,6 @@ var (
errOIDCAllowedUsers = errors.New(
"authenticated principal does not match any allowed user",
)
errOIDCInvalidNodeState = errors.New(
"requested node state key expired before authorisation completed",
)
errOIDCNodeKeyMissing = errors.New("could not get node key from cache")
)
// RegistrationInfo contains both machine key and verifier information for OIDC validation.
@@ -108,16 +104,8 @@ func (a *AuthProviderOIDC) AuthURL(registrationID types.RegistrationID) string {
registrationID.String())
}
func (a *AuthProviderOIDC) determineNodeExpiry(idTokenExpiration time.Time) time.Time {
if a.cfg.UseExpiryFromToken {
return idTokenExpiration
}
return time.Now().Add(a.cfg.Expiry)
}
// RegisterOIDC redirects to the OIDC provider for authentication
// Puts NodeKey in cache so the callback can retrieve it using the oidc state param
// RegisterHandler registers the OIDC callback handler with the given router.
// It puts NodeKey in cache so the callback can retrieve it using the oidc state param.
// Listens in /register/:registration_id.
func (a *AuthProviderOIDC) RegisterHandler(
writer http.ResponseWriter,
@@ -304,7 +292,7 @@ func (a *AuthProviderOIDC) OIDCCallbackHandler(
return
}
user, c, err := a.createOrUpdateUserFromClaim(&claims)
user, _, err := a.createOrUpdateUserFromClaim(&claims)
if err != nil {
log.Error().
Err(err).
@@ -323,9 +311,6 @@ func (a *AuthProviderOIDC) OIDCCallbackHandler(
return
}
// Send policy update notifications if needed
a.h.Change(c)
// TODO(kradalby): Is this comment right?
// If the node exists, then the node should be reauthenticated,
// if the node does not exist, and the machine key exists, then
@@ -372,6 +357,14 @@ func (a *AuthProviderOIDC) OIDCCallbackHandler(
httpError(writer, NewHTTPError(http.StatusGone, "login session expired, try again", nil))
}
func (a *AuthProviderOIDC) determineNodeExpiry(idTokenExpiration time.Time) time.Time {
if a.cfg.UseExpiryFromToken {
return idTokenExpiration
}
return time.Now().Add(a.cfg.Expiry)
}
func extractCodeAndStateParamFromRequest(
req *http.Request,
) (string, string, error) {
@@ -504,8 +497,8 @@ func (a *AuthProviderOIDC) createOrUpdateUserFromClaim(
}
// if the user is still not found, create a new empty user.
// TODO(kradalby): This might cause us to not have an ID below which
// is a problem.
// TODO(kradalby): This context is not inherited from the request, which is probably not ideal.
// However, we need a context to use the OIDC provider.
if user == nil {
newUser = true
user = &types.User{}
@@ -557,18 +550,13 @@ func (a *AuthProviderOIDC) handleRegistration(
// ensure we send an update.
// This works, but might be another good candidate for doing some sort of
// eventbus.
_ = a.h.state.AutoApproveRoutes(node)
_, policyChange, err := a.h.state.SaveNode(node)
routesChange, err := a.h.state.AutoApproveRoutes(node)
if err != nil {
return false, fmt.Errorf("saving auto approved routes to node: %w", err)
return false, fmt.Errorf("auto approving routes: %w", err)
}
// Policy updates are full and take precedence over node changes.
if !policyChange.Empty() {
a.h.Change(policyChange)
} else {
a.h.Change(nodeChange)
}
// Send both changes. Empty changes are ignored by Change().
a.h.Change(nodeChange, routesChange)
return !nodeChange.Empty(), nil
}