@@ -17,10 +17,13 @@ limitations under the License.
1717package login
1818
1919import (
20+ "errors"
2021 "fmt"
2122 "time"
2223
24+ "github.com/go-sql-driver/mysql"
2325 "github.com/golang-jwt/jwt"
26+ "github.com/google/uuid"
2427 "github.com/mojocn/base64Captcha"
2528 "github.com/patrickmn/go-cache"
2629 "go.uber.org/zap"
@@ -29,12 +32,14 @@ import (
2932 configbase "github.com/koderover/zadig/v2/pkg/config"
3033 "github.com/koderover/zadig/v2/pkg/microservice/user/config"
3134 "github.com/koderover/zadig/v2/pkg/microservice/user/core/repository"
35+ "github.com/koderover/zadig/v2/pkg/microservice/user/core/repository/models"
3236 "github.com/koderover/zadig/v2/pkg/microservice/user/core/repository/orm"
3337 "github.com/koderover/zadig/v2/pkg/microservice/user/core/service/common"
3438 "github.com/koderover/zadig/v2/pkg/setting"
3539 "github.com/koderover/zadig/v2/pkg/shared/client/aslan"
3640 "github.com/koderover/zadig/v2/pkg/shared/client/plutusvendor"
3741 zadigCache "github.com/koderover/zadig/v2/pkg/tool/cache"
42+ "github.com/koderover/zadig/v2/pkg/tool/log"
3843)
3944
4045type LoginArgs struct {
@@ -271,3 +276,137 @@ func GetCaptcha(logger *zap.SugaredLogger) (string, string, error) {
271276 }
272277 return id , b64s , nil
273278}
279+
280+ type SsoTokenClaims struct {
281+ UserID string `json:"userId"`
282+ Account string `json:"account"`
283+ jwt.StandardClaims
284+ }
285+
286+ func SsoTokenCallback (tokenString string , logger * zap.SugaredLogger ) (string , error ) {
287+ parsedToken , err := jwt .ParseWithClaims (tokenString , & SsoTokenClaims {}, func (token * jwt.Token ) (interface {}, error ) {
288+ // // 防止 alg 混淆攻击,只接受 HS256
289+ // if token.Method != jwt.SigningMethodHS256 {
290+ // return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
291+ // }
292+ return []byte (configbase .SsoTokenSecret ()), nil
293+ })
294+ if err != nil {
295+ return "" , err
296+ }
297+
298+ claims , ok := parsedToken .Claims .(* SsoTokenClaims )
299+ if ! ok || ! parsedToken .Valid {
300+ return "" , fmt .Errorf ("invalid token" )
301+ }
302+
303+ log .Infof ("[SsoTokenCallback]: userId: %s, account: %s" , claims .UserID , claims .Account )
304+
305+ var userLogin * models.UserLogin
306+ identityType := config .SsoTokenIdentityType
307+ user , err := orm .GetUser (claims .UserID , identityType , repository .DB )
308+ if err != nil {
309+ err = fmt .Errorf ("SsoTokenLogin get user account:%s error, error msg:%s" , claims .UserID , err .Error ())
310+ log .Errorf (err .Error ())
311+ return "" , err
312+ }
313+ if user == nil {
314+ uid , _ := uuid .NewUUID ()
315+ user := & models.User {
316+ Name : claims .Account ,
317+ Email : fmt .Sprintf ("%s-%s@poc.example" , claims .UserID , claims .Account ),
318+ IdentityType : config .SystemIdentityType ,
319+ Account : claims .UserID ,
320+ UID : uid .String (),
321+ }
322+
323+ tx := repository .DB .Begin ()
324+ defer func () {
325+ if r := recover (); r != nil {
326+ tx .Rollback ()
327+ }
328+ }()
329+ err = orm .CreateUser (user , tx )
330+ if err != nil {
331+ tx .Rollback ()
332+ logger .Errorf ("[SsoTokenCallback] CreateUser :%v error, error msg:%s" , user , err .Error ())
333+ var mysqlErr * mysql.MySQLError
334+ if errors .As (err , & mysqlErr ) && mysqlErr .Number == 1062 {
335+ return "" , fmt .Errorf ("存在相同用户名" )
336+ }
337+ return "" , fmt .Errorf ("创建用户失败, error: %s" , err .Error ())
338+ }
339+ userLogin := & models.UserLogin {
340+ UID : user .UID ,
341+ LastLoginTime : time .Now ().Unix (),
342+ LoginId : user .Account ,
343+ LoginType : int (config .AccountLoginType ),
344+ }
345+ err = orm .CreateUserLogin (userLogin , tx )
346+ if err != nil {
347+ tx .Rollback ()
348+ err = fmt .Errorf ("[SsoTokenCallback] CreateUserLogin:%v error, error msg:%s" , user , err .Error ())
349+ log .Errorf (err .Error ())
350+ return "" , err
351+ }
352+ if tx .Commit ().Error != nil {
353+ return "" , fmt .Errorf ("创建用户登录信息失败, error: %s" , tx .Commit ().Error )
354+ }
355+ } else {
356+ userLogin , err = orm .GetUserLogin (user .UID , claims .UserID , config .AccountLoginType , repository .DB )
357+ if err != nil {
358+ err = fmt .Errorf ("SsoTokenLogin get user:%s user login not exist, error msg:%s" , claims .UserID , err .Error ())
359+ log .Errorf (err .Error ())
360+ return "" , err
361+ }
362+ }
363+
364+ if userLogin != nil {
365+ err = CheckSignature (userLogin .LastLoginTime , logger )
366+ if err != nil {
367+ return "" , err
368+ }
369+ }
370+
371+ userLogin .LastLoginTime = time .Now ().Unix ()
372+ err = orm .UpdateUserLogin (userLogin .UID , userLogin , repository .DB )
373+ if err != nil {
374+ err = fmt .Errorf ("[SsoTokenCallback] user:%s update user login info error, error msg:%s" , claims .UserID , err .Error ())
375+ log .Errorf (err .Error ())
376+ return "" , err
377+ }
378+
379+ systemSettings , err := aslan .New (configbase .AslanServiceAddress ()).GetSystemSecurityAndPrivacySettings ()
380+ if err != nil {
381+ err = fmt .Errorf ("failed to get system security settings, error: %s" , err )
382+ log .Errorf (err .Error ())
383+ return "" , err
384+ }
385+
386+ token , err := CreateToken (& Claims {
387+ Name : user .Name ,
388+ UID : user .UID ,
389+ Email : user .Email ,
390+ PreferredUsername : user .Account ,
391+ StandardClaims : jwt.StandardClaims {
392+ Audience : setting .ProductName ,
393+ ExpiresAt : time .Now ().Add (time .Duration (systemSettings .TokenExpirationTime ) * time .Hour ).Unix (),
394+ },
395+ FederatedClaims : FederatedClaims {
396+ ConnectorId : user .IdentityType ,
397+ UserId : user .Account ,
398+ },
399+ })
400+ if err != nil {
401+ err = fmt .Errorf ("[SsoTokenCallback] user:%s create token error, error msg:%s" , claims .UserID , err .Error ())
402+ log .Errorf (err .Error ())
403+ return "" , err
404+ }
405+
406+ err = zadigCache .NewRedisCache (config .RedisUserTokenDB ()).Write (user .UID , token , time .Duration (systemSettings .TokenExpirationTime )* time .Hour )
407+ if err != nil {
408+ logger .Errorf ("failed to write token into cache, error: %s\n warn: this will cause login failure" , err )
409+ }
410+
411+ return token , nil
412+ }
0 commit comments