Browse Source

feat(oauth): Oauth nonce (#148)

lejianwen 11 months ago
parent
commit
0403d71502
4 changed files with 31 additions and 22 deletions
  1. 2 1
      http/controller/admin/login.go
  2. 6 5
      http/controller/admin/oauth.go
  3. 5 5
      http/controller/api/ouath.go
  4. 18 11
      service/oauth.go

+ 2 - 1
http/controller/admin/login.go

@@ -283,7 +283,7 @@ func (ct *Login) OidcAuth(c *gin.Context) {
283
 		return
283
 		return
284
 	}
284
 	}
285
 
285
 
286
-	err, state, verifier, url := service.AllService.OauthService.BeginAuth(f.Op)
286
+	err, state, verifier, nonce, url := service.AllService.OauthService.BeginAuth(f.Op)
287
 	if err != nil {
287
 	if err != nil {
288
 		response.Error(c, response.TranslateMsg(c, err.Error()))
288
 		response.Error(c, response.TranslateMsg(c, err.Error()))
289
 		return
289
 		return
@@ -298,6 +298,7 @@ func (ct *Login) OidcAuth(c *gin.Context) {
298
 		DeviceOs: f.DeviceInfo.Os,
298
 		DeviceOs: f.DeviceInfo.Os,
299
 		Uuid:     f.Uuid,
299
 		Uuid:     f.Uuid,
300
 		Verifier: verifier,
300
 		Verifier: verifier,
301
+		Nonce:    nonce,
301
 	}, 5*60)
302
 	}, 5*60)
302
 
303
 
303
 	response.Success(c, gin.H{
304
 	response.Success(c, gin.H{

+ 6 - 5
http/controller/admin/oauth.go

@@ -43,17 +43,18 @@ func (o *Oauth) ToBind(c *gin.Context) {
43
 		return
43
 		return
44
 	}
44
 	}
45
 
45
 
46
-	err, state, verifier, url := service.AllService.OauthService.BeginAuth(f.Op)
46
+	err, state, verifier, nonce, url := service.AllService.OauthService.BeginAuth(f.Op)
47
 	if err != nil {
47
 	if err != nil {
48
 		response.Error(c, response.TranslateMsg(c, err.Error()))
48
 		response.Error(c, response.TranslateMsg(c, err.Error()))
49
 		return
49
 		return
50
 	}
50
 	}
51
 
51
 
52
 	service.AllService.OauthService.SetOauthCache(state, &service.OauthCacheItem{
52
 	service.AllService.OauthService.SetOauthCache(state, &service.OauthCacheItem{
53
-		Action: service.OauthActionTypeBind,
54
-		Op:     	f.Op,
55
-		UserId: 	u.Id,
56
-		Verifier: 	verifier,
53
+		Action:   service.OauthActionTypeBind,
54
+		Op:       f.Op,
55
+		UserId:   u.Id,
56
+		Verifier: verifier,
57
+		Nonce:    nonce,
57
 	}, 5*60)
58
 	}, 5*60)
58
 
59
 
59
 	response.Success(c, gin.H{
60
 	response.Success(c, gin.H{

+ 5 - 5
http/controller/api/ouath.go

@@ -32,10 +32,8 @@ func (o *Oauth) OidcAuth(c *gin.Context) {
32
 	}
32
 	}
33
 
33
 
34
 	oauthService := service.AllService.OauthService
34
 	oauthService := service.AllService.OauthService
35
-	var state string
36
-	var url string
37
-	var verifier string
38
-	err, state, verifier, url = oauthService.BeginAuth(f.Op)
35
+
36
+	err, state, verifier, nonce, url := oauthService.BeginAuth(f.Op)
39
 	if err != nil {
37
 	if err != nil {
40
 		response.Error(c, response.TranslateMsg(c, err.Error()))
38
 		response.Error(c, response.TranslateMsg(c, err.Error()))
41
 		return
39
 		return
@@ -50,6 +48,7 @@ func (o *Oauth) OidcAuth(c *gin.Context) {
50
 		DeviceOs:   f.DeviceInfo.Os,
48
 		DeviceOs:   f.DeviceInfo.Os,
51
 		DeviceType: f.DeviceInfo.Type,
49
 		DeviceType: f.DeviceInfo.Type,
52
 		Verifier:   verifier,
50
 		Verifier:   verifier,
51
+		Nonce:      nonce,
53
 	}, 5*60)
52
 	}, 5*60)
54
 	//fmt.Println("code url", code, url)
53
 	//fmt.Println("code url", code, url)
55
 	c.JSON(http.StatusOK, gin.H{
54
 	c.JSON(http.StatusOK, gin.H{
@@ -160,13 +159,14 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
160
 		})
159
 		})
161
 		return
160
 		return
162
 	}
161
 	}
162
+	nonce := oauthCache.Nonce
163
 	op := oauthCache.Op
163
 	op := oauthCache.Op
164
 	action := oauthCache.Action
164
 	action := oauthCache.Action
165
 	verifier := oauthCache.Verifier
165
 	verifier := oauthCache.Verifier
166
 	var user *model.User
166
 	var user *model.User
167
 	// 获取用户信息
167
 	// 获取用户信息
168
 	code := c.Query("code")
168
 	code := c.Query("code")
169
-	err, oauthUser := oauthService.Callback(code, verifier, op)
169
+	err, oauthUser := oauthService.Callback(code, verifier, op, nonce)
170
 	if err != nil {
170
 	if err != nil {
171
 		c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
171
 		c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
172
 			"message": response.TranslateMsg(c, "OauthFailed") + response.TranslateMsg(c, err.Error()),
172
 			"message": response.TranslateMsg(c, "OauthFailed") + response.TranslateMsg(c, err.Error()),

+ 18 - 11
service/oauth.go

@@ -47,6 +47,7 @@ type OauthCacheItem struct {
47
 	Name       string `json:"name"`
47
 	Name       string `json:"name"`
48
 	Email      string `json:"email"`
48
 	Email      string `json:"email"`
49
 	Verifier   string `json:"verifier"` // used for oauth pkce
49
 	Verifier   string `json:"verifier"` // used for oauth pkce
50
+	Nonce      string `json:"nonce"`
50
 }
51
 }
51
 
52
 
52
 func (oci *OauthCacheItem) ToOauthUser() *model.OauthUser {
53
 func (oci *OauthCacheItem) ToOauthUser() *model.OauthUser {
@@ -93,17 +94,22 @@ func (os *OauthService) DeleteOauthCache(key string) {
93
 	OauthCache.Delete(key)
94
 	OauthCache.Delete(key)
94
 }
95
 }
95
 
96
 
96
-func (os *OauthService) BeginAuth(op string) (error error, state, verifier, url string) {
97
+func (os *OauthService) BeginAuth(op string) (error error, state, verifier, nonce, url string) {
97
 	state = utils.RandomString(10) + strconv.FormatInt(time.Now().Unix(), 10)
98
 	state = utils.RandomString(10) + strconv.FormatInt(time.Now().Unix(), 10)
98
 	verifier = ""
99
 	verifier = ""
100
+	nonce = ""
99
 	if op == model.OauthTypeWebauth {
101
 	if op == model.OauthTypeWebauth {
100
 		url = global.Config.Rustdesk.ApiServer + "/_admin/#/oauth/" + state
102
 		url = global.Config.Rustdesk.ApiServer + "/_admin/#/oauth/" + state
101
 		//url = "http://localhost:8888/_admin/#/oauth/" + code
103
 		//url = "http://localhost:8888/_admin/#/oauth/" + code
102
-		return nil, state, verifier, url
104
+		return nil, state, verifier, nonce, url
103
 	}
105
 	}
104
 	err, oauthInfo, oauthConfig, _ := os.GetOauthConfig(op)
106
 	err, oauthInfo, oauthConfig, _ := os.GetOauthConfig(op)
105
 	if err == nil {
107
 	if err == nil {
106
 		extras := make([]oauth2.AuthCodeOption, 0, 3)
108
 		extras := make([]oauth2.AuthCodeOption, 0, 3)
109
+
110
+		nonce = utils.RandomString(10)
111
+		extras = append(extras, oauth2.SetAuthURLParam("nonce", nonce))
112
+
107
 		if oauthInfo.PkceEnable != nil && *oauthInfo.PkceEnable {
113
 		if oauthInfo.PkceEnable != nil && *oauthInfo.PkceEnable {
108
 			extras = append(extras, oauth2.AccessTypeOffline)
114
 			extras = append(extras, oauth2.AccessTypeOffline)
109
 			verifier = oauth2.GenerateVerifier()
115
 			verifier = oauth2.GenerateVerifier()
@@ -115,10 +121,11 @@ func (os *OauthService) BeginAuth(op string) (error error, state, verifier, url
115
 				extras = append(extras, oauth2.SetAuthURLParam("code_challenge_method", "plain"), oauth2.SetAuthURLParam("code_challenge", verifier))
121
 				extras = append(extras, oauth2.SetAuthURLParam("code_challenge_method", "plain"), oauth2.SetAuthURLParam("code_challenge", verifier))
116
 			}
122
 			}
117
 		}
123
 		}
118
-		return err, state, verifier, oauthConfig.AuthCodeURL(state, extras...)
124
+
125
+		return err, state, verifier, nonce, oauthConfig.AuthCodeURL(state, extras...)
119
 	}
126
 	}
120
 
127
 
121
-	return err, state, verifier, ""
128
+	return err, state, verifier, nonce, ""
122
 }
129
 }
123
 
130
 
124
 func (os *OauthService) FetchOidcProvider(issuer string) (error, *oidc.Provider) {
131
 func (os *OauthService) FetchOidcProvider(issuer string) (error, *oidc.Provider) {
@@ -280,9 +287,9 @@ func (os *OauthService) callbackBase(oauthConfig *oauth2.Config, provider *oidc.
280
 }
287
 }
281
 
288
 
282
 // githubCallback github回调
289
 // githubCallback github回调
283
-func (os *OauthService) githubCallback(oauthConfig *oauth2.Config, provider *oidc.Provider, code string, verifier string) (error, *model.OauthUser) {
290
+func (os *OauthService) githubCallback(oauthConfig *oauth2.Config, provider *oidc.Provider, code, verifier, nonce string) (error, *model.OauthUser) {
284
 	var user = &model.GithubUser{}
291
 	var user = &model.GithubUser{}
285
-	err, client := os.callbackBase(oauthConfig, provider, code, verifier, "", user)
292
+	err, client := os.callbackBase(oauthConfig, provider, code, verifier, nonce, user)
286
 	if err != nil {
293
 	if err != nil {
287
 		return err, nil
294
 		return err, nil
288
 	}
295
 	}
@@ -294,16 +301,16 @@ func (os *OauthService) githubCallback(oauthConfig *oauth2.Config, provider *oid
294
 }
301
 }
295
 
302
 
296
 // oidcCallback oidc回调, 通过code获取用户信息
303
 // oidcCallback oidc回调, 通过code获取用户信息
297
-func (os *OauthService) oidcCallback(oauthConfig *oauth2.Config, provider *oidc.Provider, code string, verifier string) (error, *model.OauthUser) {
304
+func (os *OauthService) oidcCallback(oauthConfig *oauth2.Config, provider *oidc.Provider, code, verifier, nonce string) (error, *model.OauthUser) {
298
 	var user = &model.OidcUser{}
305
 	var user = &model.OidcUser{}
299
-	if err, _ := os.callbackBase(oauthConfig, provider, code, verifier, "", user); err != nil {
306
+	if err, _ := os.callbackBase(oauthConfig, provider, code, verifier, nonce, user); err != nil {
300
 		return err, nil
307
 		return err, nil
301
 	}
308
 	}
302
 	return nil, user.ToOauthUser()
309
 	return nil, user.ToOauthUser()
303
 }
310
 }
304
 
311
 
305
 // Callback: Get user information by code and op(Oauth provider)
312
 // Callback: Get user information by code and op(Oauth provider)
306
-func (os *OauthService) Callback(code, verifier, op string) (err error, oauthUser *model.OauthUser) {
313
+func (os *OauthService) Callback(code, verifier, op, nonce string) (err error, oauthUser *model.OauthUser) {
307
 	err, oauthInfo, oauthConfig, provider := os.GetOauthConfig(op)
314
 	err, oauthInfo, oauthConfig, provider := os.GetOauthConfig(op)
308
 	// oauthType is already validated in GetOauthConfig
315
 	// oauthType is already validated in GetOauthConfig
309
 	if err != nil {
316
 	if err != nil {
@@ -312,9 +319,9 @@ func (os *OauthService) Callback(code, verifier, op string) (err error, oauthUse
312
 	oauthType := oauthInfo.OauthType
319
 	oauthType := oauthInfo.OauthType
313
 	switch oauthType {
320
 	switch oauthType {
314
 	case model.OauthTypeGithub:
321
 	case model.OauthTypeGithub:
315
-		err, oauthUser = os.githubCallback(oauthConfig, provider, code, verifier)
322
+		err, oauthUser = os.githubCallback(oauthConfig, provider, code, verifier, nonce)
316
 	case model.OauthTypeOidc, model.OauthTypeGoogle:
323
 	case model.OauthTypeOidc, model.OauthTypeGoogle:
317
-		err, oauthUser = os.oidcCallback(oauthConfig, provider, code, verifier)
324
+		err, oauthUser = os.oidcCallback(oauthConfig, provider, code, verifier, nonce)
318
 	default:
325
 	default:
319
 		return errors.New("unsupported OAuth type"), nil
326
 		return errors.New("unsupported OAuth type"), nil
320
 	}
327
 	}