Browse Source

added azure sign in

0xdcarns 3 years ago
parent
commit
f39e16fbc9
4 changed files with 134 additions and 8 deletions
  1. 1 1
      auth/auth.go
  2. 126 0
      auth/azure-ad.go
  3. 4 4
      auth/github.go
  4. 3 3
      auth/google.go

+ 1 - 1
auth/auth.go

@@ -35,7 +35,7 @@ func getCurrentAuthFunctions() map[string]interface{} {
 	case google_provider_name:
 	case google_provider_name:
 		return google_functions
 		return google_functions
 	case azure_ad_provider_name:
 	case azure_ad_provider_name:
-		return google_functions
+		return azure_ad_functions
 	case github_provider_name:
 	case github_provider_name:
 		return github_functions
 		return github_functions
 	default:
 	default:

+ 126 - 0
auth/azure-ad.go

@@ -0,0 +1,126 @@
+package auth
+
+import (
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"net/http"
+	"os"
+
+	"github.com/gravitl/netmaker/logic"
+	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/servercfg"
+	"golang.org/x/oauth2"
+	"golang.org/x/oauth2/microsoft"
+)
+
+var azure_ad_functions = map[string]interface{}{
+	init_provider:   initAzureAD,
+	get_user_info:   getAzureUserInfo,
+	handle_callback: handleAzureCallback,
+	handle_login:    handleAzureLogin,
+	verify_user:     verifyAzureUser,
+}
+
+type azureOauthUser struct {
+	UserPrincipalName string `json:"userPrincipalName" bson:"userPrincipalName"`
+	AccessToken       string `json:"accesstoken" bson:"accesstoken"`
+}
+
+// == handle azure ad authentication here ==
+
+func initAzureAD(redirectURL string, clientID string, clientSecret string) {
+	auth_provider = &oauth2.Config{
+		RedirectURL:  redirectURL,
+		ClientID:     clientID,
+		ClientSecret: clientSecret,
+		Scopes:       []string{"User.Read"},
+		Endpoint:     microsoft.AzureADEndpoint(os.Getenv("AZURE_TENANT")),
+	}
+}
+
+func handleAzureLogin(w http.ResponseWriter, r *http.Request) {
+	oauth_state_string = logic.RandomString(16)
+	if auth_provider == nil && servercfg.GetFrontendURL() != "" {
+		http.Redirect(w, r, servercfg.GetFrontendURL()+"?oauth=callback-error", http.StatusTemporaryRedirect)
+		return
+	} else if auth_provider == nil {
+		fmt.Fprintf(w, "%s", []byte("no frontend URL was provided and an OAuth login was attempted\nplease reconfigure server to use OAuth or use basic credentials"))
+		return
+	}
+	var url = auth_provider.AuthCodeURL(oauth_state_string)
+	http.Redirect(w, r, url, http.StatusTemporaryRedirect)
+}
+
+func handleAzureCallback(w http.ResponseWriter, r *http.Request) {
+
+	var content, err = getAzureUserInfo(r.FormValue("state"), r.FormValue("code"))
+	if err != nil {
+		logic.Log("error when getting user info from azure: "+err.Error(), 1)
+		http.Redirect(w, r, servercfg.GetFrontendURL()+"?oauth=callback-error", http.StatusTemporaryRedirect)
+		return
+	}
+	_, err = logic.GetUser(content.UserPrincipalName)
+	if err != nil { // user must not exists, so try to make one
+		if err = addUser(content.UserPrincipalName); err != nil {
+			return
+		}
+	}
+	var newPass, fetchErr = fetchPassValue("")
+	if fetchErr != nil {
+		return
+	}
+	// send a netmaker jwt token
+	var authRequest = models.UserAuthParams{
+		UserName: content.UserPrincipalName,
+		Password: newPass,
+	}
+
+	var jwt, jwtErr = logic.VerifyAuthRequest(authRequest)
+	if jwtErr != nil {
+		logic.Log("could not parse jwt for user "+authRequest.UserName, 1)
+		return
+	}
+
+	logic.Log("completed azure OAuth sigin in for "+content.UserPrincipalName, 1)
+	http.Redirect(w, r, servercfg.GetFrontendURL()+"?login="+jwt+"&user="+content.UserPrincipalName, http.StatusPermanentRedirect)
+}
+
+func getAzureUserInfo(state string, code string) (*azureOauthUser, error) {
+	if state != oauth_state_string {
+		return nil, fmt.Errorf("invalid oauth state")
+	}
+	var token, err = auth_provider.Exchange(oauth2.NoContext, code)
+	if err != nil {
+		return nil, fmt.Errorf("code exchange failed: %s", err.Error())
+	}
+	var data []byte
+	data, err = json.Marshal(token)
+	if err != nil {
+		return nil, fmt.Errorf("failed to convert token to json: %s", err.Error())
+	}
+	var httpReq, reqErr = http.NewRequest("GET", "https://graph.microsoft.com/v1.0/me", nil)
+	if reqErr != nil {
+		return nil, fmt.Errorf("failed to create request to GitHub")
+	}
+	httpReq.Header.Set("Authorization", "Bearer "+token.AccessToken)
+	response, err := http.DefaultClient.Do(httpReq)
+	if err != nil {
+		return nil, fmt.Errorf("failed getting user info: %s", err.Error())
+	}
+	defer response.Body.Close()
+	contents, err := ioutil.ReadAll(response.Body)
+	if err != nil {
+		return nil, fmt.Errorf("failed reading response body: %s", err.Error())
+	}
+	var userInfo = &azureOauthUser{}
+	if err = json.Unmarshal(contents, userInfo); err != nil {
+		return nil, fmt.Errorf("failed parsing email from response data: %s", err.Error())
+	}
+	userInfo.AccessToken = string(data)
+	return userInfo, nil
+}
+
+func verifyAzureUser(token *oauth2.Token) bool {
+	return token.Valid()
+}

+ 4 - 4
auth/github.go

@@ -26,7 +26,7 @@ type githubOauthUser struct {
 	AccessToken string `json:"accesstoken" bson:"accesstoken"`
 	AccessToken string `json:"accesstoken" bson:"accesstoken"`
 }
 }
 
 
-// == handle google authentication here ==
+// == handle github authentication here ==
 
 
 func initGithub(redirectURL string, clientID string, clientSecret string) {
 func initGithub(redirectURL string, clientID string, clientSecret string) {
 	auth_provider = &oauth2.Config{
 	auth_provider = &oauth2.Config{
@@ -81,13 +81,13 @@ func handleGithubCallback(w http.ResponseWriter, r *http.Request) {
 		return
 		return
 	}
 	}
 
 
-	logic.Log("completed github oauth sigin in for "+content.Login, 0)
-	http.Redirect(w, r, servercfg.GetFrontendURL()+"?login="+jwt+"&email="+content.Login, http.StatusPermanentRedirect)
+	logic.Log("completed github OAuth sigin in for "+content.Login, 1)
+	http.Redirect(w, r, servercfg.GetFrontendURL()+"?login="+jwt+"&user="+content.Login, http.StatusPermanentRedirect)
 }
 }
 
 
 func getGithubUserInfo(state string, code string) (*githubOauthUser, error) {
 func getGithubUserInfo(state string, code string) (*githubOauthUser, error) {
 	if state != oauth_state_string {
 	if state != oauth_state_string {
-		return nil, fmt.Errorf("invalid oauth state")
+		return nil, fmt.Errorf("invalid OAuth state")
 	}
 	}
 	var token, err = auth_provider.Exchange(oauth2.NoContext, code)
 	var token, err = auth_provider.Exchange(oauth2.NoContext, code)
 	if err != nil {
 	if err != nil {

+ 3 - 3
auth/google.go

@@ -81,13 +81,13 @@ func handleGoogleCallback(w http.ResponseWriter, r *http.Request) {
 		return
 		return
 	}
 	}
 
 
-	logic.Log("completed google oauth sigin in for "+content.Email, 0)
-	http.Redirect(w, r, servercfg.GetFrontendURL()+"?login="+jwt+"&email="+content.Email, http.StatusPermanentRedirect)
+	logic.Log("completed google OAuth sigin in for "+content.Email, 1)
+	http.Redirect(w, r, servercfg.GetFrontendURL()+"?login="+jwt+"&user="+content.Email, http.StatusPermanentRedirect)
 }
 }
 
 
 func getGoogleUserInfo(state string, code string) (*googleOauthUser, error) {
 func getGoogleUserInfo(state string, code string) (*googleOauthUser, error) {
 	if state != oauth_state_string {
 	if state != oauth_state_string {
-		return nil, fmt.Errorf("invalid oauth state")
+		return nil, fmt.Errorf("invalid OAuth state")
 	}
 	}
 	var token, err = auth_provider.Exchange(oauth2.NoContext, code)
 	var token, err = auth_provider.Exchange(oauth2.NoContext, code)
 	if err != nil {
 	if err != nil {