Merge pull request #7567 from reasonerjt/oidc-google-refresh-token

Persist the new token in DB after login
This commit is contained in:
Wenkai Yin 2019-04-28 14:12:25 +08:00 committed by GitHub
commit 7af679af7e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 25 additions and 6 deletions

View File

@ -148,8 +148,8 @@ func AuthCodeURL(state string) (string, error) {
log.Errorf("Failed to get OAuth configuration, error: %v", err) log.Errorf("Failed to get OAuth configuration, error: %v", err)
return "", err return "", err
} }
if strings.HasPrefix(conf.Endpoint.AuthURL, googleEndpoint) { if strings.HasPrefix(conf.Endpoint.AuthURL, googleEndpoint) { // make sure the refresh token will be returned
return conf.AuthCodeURL(state, oauth2.AccessTypeOffline), nil return conf.AuthCodeURL(state, oauth2.AccessTypeOffline, oauth2.SetAuthURLParam("prompt", "consent")), nil
} }
return conf.AuthCodeURL(state), nil return conf.AuthCodeURL(state), nil
} }

View File

@ -102,6 +102,7 @@ func (dm *defaultManager) VerifyToken(ctx context.Context, user *models.OIDCUser
if err != nil { if err != nil {
return verifyError(err) return verifyError(err)
} }
log.Debugf("Token string for verify: %s", tokenStr)
_, err = VerifyToken(ctx, token.IDToken) _, err = VerifyToken(ctx, token.IDToken)
if err == nil { if err == nil {
return nil return nil

View File

@ -33,6 +33,7 @@ import (
const tokenKey = "oidc_token" const tokenKey = "oidc_token"
const stateKey = "oidc_state" const stateKey = "oidc_state"
const userInfoKey = "oidc_user_info" const userInfoKey = "oidc_user_info"
const oidcUserComment = "Onboarded via OIDC provider"
// OIDCController handles requests for OIDC login, callback and user onboard // OIDCController handles requests for OIDC login, callback and user onboard
type OIDCController struct { type OIDCController struct {
@ -67,6 +68,7 @@ func (oc *OIDCController) RedirectLogin() {
return return
} }
oc.SetSession(stateKey, state) oc.SetSession(stateKey, state)
log.Debugf("State dumped to session: %s", state)
// Force to use the func 'Redirect' of beego.Controller // Force to use the func 'Redirect' of beego.Controller
oc.Controller.Redirect(url, http.StatusFound) oc.Controller.Redirect(url, http.StatusFound)
} }
@ -75,6 +77,8 @@ func (oc *OIDCController) RedirectLogin() {
// kick off onboard if needed. // kick off onboard if needed.
func (oc *OIDCController) Callback() { func (oc *OIDCController) Callback() {
if oc.Ctx.Request.URL.Query().Get("state") != oc.GetSession(stateKey) { if oc.Ctx.Request.URL.Query().Get("state") != oc.GetSession(stateKey) {
log.Errorf("State mismatch, in session: %s, in url: %s", oc.GetSession(stateKey),
oc.Ctx.Request.URL.Query().Get("state"))
oc.SendBadRequestError(errors.New("State mismatch")) oc.SendBadRequestError(errors.New("State mismatch"))
return return
} }
@ -106,21 +110,34 @@ func (oc *OIDCController) Callback() {
oc.SendInternalServerError(err) oc.SendInternalServerError(err)
return return
} }
tokenBytes, err := json.Marshal(token) tokenBytes, err := json.Marshal(token)
if err != nil { if err != nil {
oc.SendInternalServerError(err) oc.SendInternalServerError(err)
return return
} }
log.Debugf("Exchanged token string: %s", string(tokenBytes))
oc.SetSession(tokenKey, tokenBytes) oc.SetSession(tokenKey, tokenBytes)
if u == nil { if u == nil {
oc.SetSession(userInfoKey, string(ouDataStr)) oc.SetSession(userInfoKey, string(ouDataStr))
oc.Controller.Redirect("/oidc-onboard", http.StatusFound) oc.Controller.Redirect(fmt.Sprintf("/oidc-onboard?username=%s", strings.Replace(d.Username, " ", "_", -1)),
http.StatusFound)
} else { } else {
oidcUser, err := dao.GetOIDCUserByUserID(u.UserID)
if err != nil {
oc.SendInternalServerError(err)
return
}
_, t, err := secretAndToken(tokenBytes)
oidcUser.Token = t
if err := dao.UpdateOIDCUser(oidcUser); err != nil {
oc.SendInternalServerError(err)
return
}
oc.SetSession(userKey, *u) oc.SetSession(userKey, *u)
oc.Controller.Redirect("/", http.StatusFound) oc.Controller.Redirect("/", http.StatusFound)
} }
} }
// Onboard handles the request to onboard an user authenticated via OIDC provider // Onboard handles the request to onboard an user authenticated via OIDC provider
@ -170,18 +187,19 @@ func (oc *OIDCController) Onboard() {
email := d.Email email := d.Email
if email == "" { if email == "" {
email = utils.GenerateRandomString() + "@harbor.com" email = utils.GenerateRandomString() + "@placeholder.com"
} }
user := models.User{ user := models.User{
Username: username, Username: username,
Email: email, Email: email,
OIDCUserMeta: &oidcUser, OIDCUserMeta: &oidcUser,
Comment: oidcUserComment,
} }
err = dao.OnBoardOIDCUser(&user) err = dao.OnBoardOIDCUser(&user)
if err != nil { if err != nil {
if strings.Contains(err.Error(), dao.ErrDupUser.Error()) { if strings.Contains(err.Error(), dao.ErrDupUser.Error()) {
oc.RenderError(http.StatusConflict, "Duplicate username") oc.RenderError(http.StatusConflict, "Conflict in username, the user with same username has been onboarded.")
return return
} }
oc.SendInternalServerError(err) oc.SendInternalServerError(err)