@@ -76,20 +76,52 @@ func (h *Headscale) RegisterOIDC(
76
76
) {
77
77
vars := mux .Vars (req )
78
78
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
- }
87
79
88
80
log .Trace ().
89
81
Caller ().
90
82
Str ("node_key" , nodeKeyStr ).
91
83
Msg ("Received oidc register call" )
92
84
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
+
93
125
randomBlob := make ([]byte , randomByteSize )
94
126
if _ , err := rand .Read (randomBlob ); err != nil {
95
127
log .Error ().
@@ -103,7 +135,7 @@ func (h *Headscale) RegisterOIDC(
103
135
stateStr := hex .EncodeToString (randomBlob )[:32 ]
104
136
105
137
// 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 )
107
139
108
140
// Add any extra parameter provided in the configuration to the Authorize Endpoint request
109
141
extras := make ([]oauth2.AuthCodeOption , 0 , len (h .cfg .OIDC .ExtraParams ))
@@ -405,8 +437,8 @@ func (h *Headscale) validateMachineForOIDCCallback(
405
437
claims * IDTokenClaims ,
406
438
) (* key.NodePublic , bool , error ) {
407
439
// 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 {
410
442
log .Error ().
411
443
Msg ("requested machine state key expired before authorisation completed" )
412
444
writer .Header ().Set ("Content-Type" , "text/plain; charset=utf-8" )
@@ -423,39 +455,42 @@ func (h *Headscale) validateMachineForOIDCCallback(
423
455
}
424
456
425
457
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 {
431
460
log .Error ().
432
- Msg ("could not parse node public key " )
461
+ Msg ("requested machine state key is not a string " )
433
462
writer .Header ().Set ("Content-Type" , "text/plain; charset=utf-8" )
434
463
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 {
437
466
log .Error ().
438
467
Caller ().
439
- Err (werr ).
468
+ Err (err ).
440
469
Msg ("Failed to write response" )
441
470
}
442
471
443
- return nil , false , err
472
+ return nil , false , errOIDCInvalidMachineState
444
473
}
445
474
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" )
448
483
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 {
452
487
log .Error ().
453
488
Caller ().
454
- Err (err ).
489
+ Err (werr ).
455
490
Msg ("Failed to write response" )
456
491
}
457
492
458
- return nil , false , errOIDCNodeKeyMissing
493
+ return nil , false , err
459
494
}
460
495
461
496
// retrieve machine information if it exist
0 commit comments