2021-09-26 16:53:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								package  headscale 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								import  ( 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-06 17:19:15 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									"context" 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-26 16:53:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									"crypto/rand" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									"encoding/hex" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									"fmt" 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-18 19:27:52 +00:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									"net/http" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									"regexp" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									"strings" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									"time" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-10-06 17:19:15 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									"github.com/coreos/go-oidc/v3/oidc" 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-26 16:53:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									"github.com/gin-gonic/gin" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									"github.com/patrickmn/go-cache" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									"github.com/rs/zerolog/log" 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-06 17:19:15 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									"golang.org/x/oauth2" 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-26 16:53:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-10-06 17:19:15 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								type  IDTokenClaims  struct  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-26 16:53:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									Name      string    ` json:"name,omitempty" ` 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									Groups    [ ] string  ` json:"groups,omitempty" ` 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									Email     string    ` json:"email" ` 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									Username  string    ` json:"preferred_username,omitempty" ` 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-10-08 17:43:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								func  ( h  * Headscale )  initOIDC ( )  error  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-26 16:53:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									var  err  error 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									// grab oidc config if it hasn't been already 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-08 17:43:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  h . oauth2Config  ==  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-18 19:27:52 +00:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										h . oidcProvider ,  err  =  oidc . NewProvider ( context . Background ( ) ,  h . cfg . OIDC . Issuer ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-26 16:53:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-06 17:19:15 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											log . Error ( ) . Msgf ( "Could not retrieve OIDC Config: %s" ,  err . Error ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-08 17:43:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											return  err 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-26 16:53:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-06 17:19:15 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-10-08 17:43:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										h . oauth2Config  =  & oauth2 . Config { 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-18 19:27:52 +00:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											ClientID :      h . cfg . OIDC . ClientID , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											ClientSecret :  h . cfg . OIDC . ClientSecret , 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-08 17:43:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											Endpoint :      h . oidcProvider . Endpoint ( ) , 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-08 15:26:31 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											RedirectURL :   fmt . Sprintf ( "%s/oidc/callback" ,  strings . TrimSuffix ( h . cfg . ServerURL ,  "/" ) ) , 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-06 17:19:15 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											Scopes :        [ ] string { oidc . ScopeOpenID ,  "profile" ,  "email" } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-08 17:43:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									// init the state cache if it hasn't been already 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  h . oidcStateCache  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										h . oidcStateCache  =  cache . New ( time . Minute * 5 ,  time . Minute * 10 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-06 17:19:15 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-10-08 17:43:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									return  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// RegisterOIDC redirects to the OIDC provider for authentication 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Puts machine key in cache so the callback can retrieve it using the oidc state param 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Listens in /oidc/register/:mKey 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( h  * Headscale )  RegisterOIDC ( c  * gin . Context )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									mKeyStr  :=  c . Param ( "mkey" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  mKeyStr  ==  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										c . String ( http . StatusBadRequest ,  "Wrong params" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-26 16:53:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									b  :=  make ( [ ] byte ,  16 ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-08 17:43:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									_ ,  err  :=  rand . Read ( b ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-26 21:12:36 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										log . Error ( ) . Msg ( "could not read 16 bytes from rand" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										c . String ( http . StatusInternalServerError ,  "could not read 16 bytes from rand" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-09-26 16:53:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									stateStr  :=  hex . EncodeToString ( b ) [ : 32 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									// place the machine key into the state cache, so it can be retrieved later 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-08 17:43:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									h . oidcStateCache . Set ( stateStr ,  mKeyStr ,  time . Minute * 5 ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-26 16:53:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-10-08 17:43:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									authUrl  :=  h . oauth2Config . AuthCodeURL ( stateStr ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-06 17:19:15 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									log . Debug ( ) . Msgf ( "Redirecting to %s for authentication" ,  authUrl ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-26 16:53:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									c . Redirect ( http . StatusFound ,  authUrl ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// OIDCCallback handles the callback from the OIDC endpoint 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-06 17:19:15 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// Retrieves the mkey from the state cache and adds the machine to the users email namespace 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// TODO: A confirmation page for new machines should be added to avoid phishing vulnerabilities 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// TODO: Add groups information from OIDC tokens into machine HostInfo 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-26 16:53:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								// Listens in /oidc/callback 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( h  * Headscale )  OIDCCallback ( c  * gin . Context )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									code  :=  c . Query ( "code" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									state  :=  c . Query ( "state" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  code  ==  ""  ||  state  ==  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										c . String ( http . StatusBadRequest ,  "Wrong params" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-10-08 17:43:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									oauth2Token ,  err  :=  h . oauth2Config . Exchange ( context . Background ( ) ,  code ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-26 16:53:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										c . String ( http . StatusBadRequest ,  "Could not exchange code for token" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-10-10 17:22:42 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									log . Debug ( ) . Msgf ( "AccessToken: %v" ,  oauth2Token . AccessToken ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-10-06 17:19:15 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									rawIDToken ,  rawIDTokenOK  :=  oauth2Token . Extra ( "id_token" ) . ( string ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  ! rawIDTokenOK  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										c . String ( http . StatusBadRequest ,  "Could not extract ID Token" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-10-18 19:27:52 +00:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									verifier  :=  h . oidcProvider . Verifier ( & oidc . Config { ClientID :  h . cfg . OIDC . ClientID } ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-26 16:53:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-10-06 17:19:15 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									idToken ,  err  :=  verifier . Verify ( context . Background ( ) ,  rawIDToken ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-26 16:53:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-06 17:19:15 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										c . String ( http . StatusBadRequest ,  "Failed to verify id token: %s" ,  err . Error ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-10-10 17:22:42 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									// TODO: we can use userinfo at some point to grab additional information about the user (groups membership, etc) 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-06 17:19:15 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									//userInfo, err := oidcProvider.UserInfo(context.Background(), oauth2.StaticTokenSource(oauth2Token)) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									//if err != nil { 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-10 17:22:42 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									//	c.String(http.StatusBadRequest, fmt.Sprintf("Failed to retrieve userinfo: %s", err)) 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-06 17:19:15 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									//	return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									//} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									// Extract custom claims 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									var  claims  IDTokenClaims 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  =  idToken . Claims ( & claims ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-10 17:22:42 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										c . String ( http . StatusBadRequest ,  fmt . Sprintf ( "Failed to decode id token claims: %s" ,  err ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-26 16:53:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-10-18 19:27:52 +00:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									// retrieve machinekey from state cache 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-08 17:43:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									mKeyIf ,  mKeyFound  :=  h . oidcStateCache . Get ( state ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-26 16:53:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  ! mKeyFound  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-10 17:22:42 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										log . Error ( ) . Msg ( "requested machine state key expired before authorisation completed" ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-26 16:53:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										c . String ( http . StatusBadRequest ,  "state has expired" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									mKeyStr ,  mKeyOK  :=  mKeyIf . ( string ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  ! mKeyOK  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-10 17:22:42 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										log . Error ( ) . Msg ( "could not get machine key from cache" ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-26 16:53:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										c . String ( http . StatusInternalServerError ,  "could not get machine key from cache" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									// retrieve machine information 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-10 17:22:42 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									m ,  err  :=  h . GetMachineByMachineKey ( mKeyStr ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-26 16:53:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										log . Error ( ) . Msg ( "machine key not found in database" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										c . String ( http . StatusInternalServerError ,  "could not get machine info from database" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-10-10 17:22:42 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									now  :=  time . Now ( ) . UTC ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-10-18 19:27:52 +00:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  nsName ,  ok  :=  h . getNamespaceFromEmail ( claims . Email ) ;  ok  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										// register the machine if it's new 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  ! m . Registered  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-26 16:53:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-10-18 19:27:52 +00:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											log . Debug ( ) . Msg ( "Registering new machine after successful callback" ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-08 17:43:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-10-18 19:27:52 +00:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											ns ,  err  :=  h . GetNamespace ( nsName ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												ns ,  err  =  h . CreateNamespace ( nsName ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													log . Error ( ) . Msgf ( "could not create new namespace '%s'" ,  claims . Email ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													c . String ( http . StatusInternalServerError ,  "could not create new namespace" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-26 21:12:36 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-10-18 19:27:52 +00:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											ip ,  err  :=  h . getAvailableIP ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-26 21:12:36 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-18 19:27:52 +00:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
												c . String ( http . StatusInternalServerError ,  "could not get an IP from the pool" ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-26 21:12:36 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
												return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-26 16:53:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-10-18 19:27:52 +00:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											m . IPAddress  =  ip . String ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											m . NamespaceID  =  ns . ID 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											m . Registered  =  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											m . RegisterMethod  =  "oidc" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											m . LastSuccessfulUpdate  =  & now 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											h . db . Save ( & m ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-26 16:53:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-10-18 19:27:52 +00:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										h . updateMachineExpiry ( m ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-26 16:53:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-10-18 19:27:52 +00:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										c . Data ( http . StatusOK ,  "text/html; charset=utf-8" ,  [ ] byte ( fmt . Sprintf ( ` 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-26 16:53:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								< html > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								< body > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								< h1 > headscale < / h1 > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								< p > 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-26 21:12:36 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    Authenticated  as  % s ,  you  can  now  close  this  window . 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-26 16:53:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								< / p > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								< / body > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								< / html > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-09-26 21:12:36 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								` ,  claims . Email ) ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-18 19:27:52 +00:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									log . Error ( ) . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										Str ( "email" ,  claims . Email ) . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										Str ( "username" ,  claims . Username ) . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										Str ( "machine" ,  m . Name ) . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										Msg ( "Email could not be mapped to a namespace" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									c . String ( http . StatusBadRequest ,  "email from claim could not be mapped to a namespace" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-10-19 18:25:59 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// getNamespaceFromEmail passes the users email through a list of "matchers" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// and iterates through them until it matches and returns a namespace. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// If no match is found, an empty string will be returned. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// TODO(kradalby): golang Maps key order is not stable, so this list is _not_ deterministic. Find a way to make the list of keys stable, preferably in the order presented in a users configuration. 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-18 19:27:52 +00:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								func  ( h  * Headscale )  getNamespaceFromEmail ( email  string )  ( string ,  bool )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									for  match ,  namespace  :=  range  h . cfg . OIDC . MatchMap  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										regex  :=  regexp . MustCompile ( match ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  regex . MatchString ( email )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											return  namespace ,  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									return  "" ,  false 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-26 16:53:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								}