Skip to content

Commit b87e1ef

Browse files
author
Juan Font
committed
OIDC code cleanup and harmonize with regular web auth
1 parent 89ff5c8 commit b87e1ef

File tree

1 file changed

+63
-28
lines changed

1 file changed

+63
-28
lines changed

oidc.go

+63-28
Original file line numberDiff line numberDiff line change
@@ -76,20 +76,52 @@ func (h *Headscale) RegisterOIDC(
7676
) {
7777
vars := mux.Vars(req)
7878
nodeKeyStr, ok := vars["nkey"]
79-
if !ok || nodeKeyStr == "" {
80-
log.Error().
81-
Caller().
82-
Msg("Missing node key in URL")
83-
http.Error(writer, "Missing node key in URL", http.StatusBadRequest)
84-
85-
return
86-
}
8779

8880
log.Trace().
8981
Caller().
9082
Str("node_key", nodeKeyStr).
9183
Msg("Received oidc register call")
9284

85+
if !NodePublicKeyRegex.Match([]byte(nodeKeyStr)) {
86+
log.Warn().Str("node_key", nodeKeyStr).Msg("Invalid node key passed to registration url")
87+
88+
writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
89+
writer.WriteHeader(http.StatusUnauthorized)
90+
_, err := writer.Write([]byte("Unauthorized"))
91+
if err != nil {
92+
log.Error().
93+
Caller().
94+
Err(err).
95+
Msg("Failed to write response")
96+
}
97+
98+
return
99+
}
100+
101+
// We need to make sure we dont open for XSS style injections, if the parameter that
102+
// is passed as a key is not parsable/validated as a NodePublic key, then fail to render
103+
// the template and log an error.
104+
var nodeKey key.NodePublic
105+
err := nodeKey.UnmarshalText(
106+
[]byte(NodePublicKeyEnsurePrefix(nodeKeyStr)),
107+
)
108+
109+
if !ok || nodeKeyStr == "" || err != nil {
110+
log.Warn().Err(err).Msg("Failed to parse incoming nodekey")
111+
112+
writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
113+
writer.WriteHeader(http.StatusBadRequest)
114+
_, err := writer.Write([]byte("Wrong params"))
115+
if err != nil {
116+
log.Error().
117+
Caller().
118+
Err(err).
119+
Msg("Failed to write response")
120+
}
121+
122+
return
123+
}
124+
93125
randomBlob := make([]byte, randomByteSize)
94126
if _, err := rand.Read(randomBlob); err != nil {
95127
log.Error().
@@ -103,7 +135,7 @@ func (h *Headscale) RegisterOIDC(
103135
stateStr := hex.EncodeToString(randomBlob)[:32]
104136

105137
// place the node key into the state cache, so it can be retrieved later
106-
h.registrationCache.Set(stateStr, nodeKeyStr, registerCacheExpiration)
138+
h.registrationCache.Set(stateStr, NodePublicKeyStripPrefix(nodeKey), registerCacheExpiration)
107139

108140
// Add any extra parameter provided in the configuration to the Authorize Endpoint request
109141
extras := make([]oauth2.AuthCodeOption, 0, len(h.cfg.OIDC.ExtraParams))
@@ -405,8 +437,8 @@ func (h *Headscale) validateMachineForOIDCCallback(
405437
claims *IDTokenClaims,
406438
) (*key.NodePublic, bool, error) {
407439
// retrieve machinekey from state cache
408-
machineKeyIf, machineKeyFound := h.registrationCache.Get(state)
409-
if !machineKeyFound {
440+
nodeKeyIf, nodeKeyFound := h.registrationCache.Get(state)
441+
if !nodeKeyFound {
410442
log.Error().
411443
Msg("requested machine state key expired before authorisation completed")
412444
writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
@@ -423,39 +455,42 @@ func (h *Headscale) validateMachineForOIDCCallback(
423455
}
424456

425457
var nodeKey key.NodePublic
426-
nodeKeyFromCache, nodeKeyOK := machineKeyIf.(string)
427-
err := nodeKey.UnmarshalText(
428-
[]byte(NodePublicKeyEnsurePrefix(nodeKeyFromCache)),
429-
)
430-
if err != nil {
458+
nodeKeyFromCache, nodeKeyOK := nodeKeyIf.(string)
459+
if !nodeKeyOK {
431460
log.Error().
432-
Msg("could not parse node public key")
461+
Msg("requested machine state key is not a string")
433462
writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
434463
writer.WriteHeader(http.StatusBadRequest)
435-
_, werr := writer.Write([]byte("could not parse public key"))
436-
if werr != nil {
464+
_, err := writer.Write([]byte("state is invalid"))
465+
if err != nil {
437466
log.Error().
438467
Caller().
439-
Err(werr).
468+
Err(err).
440469
Msg("Failed to write response")
441470
}
442471

443-
return nil, false, err
472+
return nil, false, errOIDCInvalidMachineState
444473
}
445474

446-
if !nodeKeyOK {
447-
log.Error().Msg("could not get node key from cache")
475+
err := nodeKey.UnmarshalText(
476+
[]byte(NodePublicKeyEnsurePrefix(nodeKeyFromCache)),
477+
)
478+
if err != nil {
479+
log.Error().
480+
Str("nodeKey", nodeKeyFromCache).
481+
Bool("nodeKeyOK", nodeKeyOK).
482+
Msg("could not parse node public key")
448483
writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
449-
writer.WriteHeader(http.StatusInternalServerError)
450-
_, err := writer.Write([]byte("could not get node key from cache"))
451-
if err != nil {
484+
writer.WriteHeader(http.StatusBadRequest)
485+
_, werr := writer.Write([]byte("could not parse node public key"))
486+
if werr != nil {
452487
log.Error().
453488
Caller().
454-
Err(err).
489+
Err(werr).
455490
Msg("Failed to write response")
456491
}
457492

458-
return nil, false, errOIDCNodeKeyMissing
493+
return nil, false, err
459494
}
460495

461496
// retrieve machine information if it exist

0 commit comments

Comments
 (0)