From 8b6745a2a03e48e8f5d99be7f0ca07112621488c Mon Sep 17 00:00:00 2001 From: Ross Reedstrom Date: Fri, 9 Aug 2019 12:35:22 -0500 Subject: [PATCH 1/3] don't clobber username if present --- pkg/structs/structs.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/structs/structs.go b/pkg/structs/structs.go index 81d96e6b..3451e313 100644 --- a/pkg/structs/structs.go +++ b/pkg/structs/structs.go @@ -26,7 +26,9 @@ type User struct { // PrepareUserData implement PersonalData interface func (u *User) PrepareUserData() { - u.Username = u.Email + if u.Username == "" { + u.Username = u.Email + } } // GoogleUser is a retrieved and authentiacted user from Google. From 6edeb1dd59226031d5f2b4b8c65385a9186edee6 Mon Sep 17 00:00:00 2001 From: Ross Reedstrom Date: Fri, 9 Aug 2019 15:36:22 -0500 Subject: [PATCH 2/3] test for valid provider --- pkg/cfg/cfg.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index a71382c0..8a3ecadb 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -315,6 +315,14 @@ func Get(key string) string { // BasicTest just a quick sanity check to see if the config is sound func BasicTest() error { + if GenOAuth.Provider != Providers.Google && + GenOAuth.Provider != Providers.GitHub && + GenOAuth.Provider != Providers.IndieAuth && + GenOAuth.Provider != Providers.ADFS && + GenOAuth.Provider != Providers.OIDC { + return errors.New("configuration error: Unkown oauth provider: "+ GenOAuth.Provider) + } + for _, opt := range RequiredOptions { if !viper.IsSet(opt) { return errors.New("configuration error: required configuration option " + opt + " is not set") @@ -530,6 +538,7 @@ func SetDefaults() { setDefaultsADFS() configureOAuthClient() } else { + // IndieAuth, OIDC configureOAuthClient() } } From 687c40c3ea39538cb68de2258de6420add7c405d Mon Sep 17 00:00:00 2001 From: Ross Reedstrom Date: Fri, 9 Aug 2019 16:41:47 -0500 Subject: [PATCH 3/3] add OpenStax provider --- handlers/handlers.go | 38 +++++++++++++++++++++++++++++++++++++- pkg/cfg/cfg.go | 7 +++++-- pkg/structs/structs.go | 25 +++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 3 deletions(-) diff --git a/handlers/handlers.go b/handlers/handlers.go index 0a9c3f3b..bf4d928e 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -525,10 +525,14 @@ func getUserInfo(r *http.Request, user *structs.User, customClaims *structs.Cust return err } ptokens.PAccessToken = providerToken.AccessToken + if cfg.GenOAuth.Provider == cfg.Providers.OpenStax { + client := cfg.OAuthClient.Client(context.TODO(), providerToken) + return getUserInfoFromOpenStax(client, user, customClaims, providerToken) + } ptokens.PIdToken = providerToken.Extra("id_token").(string) log.Debugf("ptokens: %+v", ptokens) - // make the "third leg" request back to google to exchange the token for the userinfo + // make the "third leg" request back to provider to exchange the token for the userinfo client := cfg.OAuthClient.Client(context.TODO(), providerToken) if cfg.GenOAuth.Provider == cfg.Providers.Google { return getUserInfoFromGoogle(client, user, customClaims) @@ -565,6 +569,38 @@ func getUserInfoFromOpenID(client *http.Client, user *structs.User, customClaims return nil } + +func getUserInfoFromOpenStax(client *http.Client, user *structs.User, customClaims *structs.CustomClaims, ptoken *oauth2.Token) (rerr error) { + userinfo, err := client.Get(cfg.GenOAuth.UserInfoURL) + if err != nil { + return err + } + defer func() { + if err := userinfo.Body.Close(); err != nil { + rerr = err + } + }() + data, _ := ioutil.ReadAll(userinfo.Body) + log.Infof("OpenID userinfo body: ", string(data)) + if err = mapClaims(data, customClaims); err != nil { + log.Error(err) + return err + } + oxUser := structs.OpenStaxUser{} + if err = json.Unmarshal(data, &oxUser); err != nil { + log.Error(err) + return err + } + + oxUser.PrepareUserData() + user.Email = oxUser.Email + user.Name = oxUser.Name + user.Username = oxUser.Username + user.ID = oxUser.ID + user.PrepareUserData() + return nil +} + func getUserInfoFromGoogle(client *http.Client, user *structs.User, customClaims *structs.CustomClaims) (rerr error) { userinfo, err := client.Get(cfg.GenOAuth.UserInfoURL) if err != nil { diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 8a3ecadb..47c6d03f 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -91,6 +91,7 @@ type OAuthProviders struct { IndieAuth string ADFS string OIDC string + OpenStax string } type branding struct { @@ -126,6 +127,7 @@ var ( IndieAuth: "indieauth", ADFS: "adfs", OIDC: "oidc", + OpenStax: "openstax", } // RequiredOptions must have these fields set for minimum viable config @@ -319,7 +321,8 @@ func BasicTest() error { GenOAuth.Provider != Providers.GitHub && GenOAuth.Provider != Providers.IndieAuth && GenOAuth.Provider != Providers.ADFS && - GenOAuth.Provider != Providers.OIDC { + GenOAuth.Provider != Providers.OIDC && + GenOAuth.Provider != Providers.OpenStax { return errors.New("configuration error: Unkown oauth provider: "+ GenOAuth.Provider) } @@ -538,7 +541,7 @@ func SetDefaults() { setDefaultsADFS() configureOAuthClient() } else { - // IndieAuth, OIDC + // IndieAuth, OIDC, OpenStax configureOAuthClient() } } diff --git a/pkg/structs/structs.go b/pkg/structs/structs.go index 3451e313..c111c8cd 100644 --- a/pkg/structs/structs.go +++ b/pkg/structs/structs.go @@ -95,6 +95,31 @@ func (u *IndieAuthUser) PrepareUserData() { u.Username = u.URL } +type Contact struct { + Type string `json:"type"` + Value string `json:"value"` + Verified bool `json:"is_verified"` +} + +//OpenStaxUser is a retrieved and authenticated user from OpenStax Accounts +type OpenStaxUser struct { + User + Contacts []Contact `json:"contact_infos"` +} + +// PrepareUserData implement PersonalData interface +func (u *OpenStaxUser) PrepareUserData() { + if u.Email == "" { + // assuming first contact of type "EmailAddress" + for _, c := range u.Contacts { + if c.Type == "EmailAddress" && c.Verified { + u.Email = c.Value + break + } + } + } +} + // Team has members and provides acess to sites type Team struct { Name string `json:"name" mapstructure:"name"`