123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272 |
- package zllauth1
- import (
- "crypto/rand"
- "encoding/hex"
- "encoding/json"
- "fmt"
- "github.com/dgrijalva/jwt-go"
- "github.com/tjfoc/gmsm/sm2"
- "time"
- )
- const zllauthSubject = "zllauth1-auth"
- type ZLLAuthHandler struct {
- config ZLLAuthConfig
- isSecureInit bool
- sm2key *sm2.PrivateKey
- sm2pubkey string
- }
- func NewZLLAuthHandler(config ZLLAuthConfig) *ZLLAuthHandler {
- o := &ZLLAuthHandler{
- config: config,
- isSecureInit: false,
- }
- return o
- }
- func (h *ZLLAuthHandler) InitSecure() error {
- pk, err := sm2.GenerateKey(rand.Reader)
- if err != nil {
- return err
- }
- h.sm2key = pk
- xenc := hex.EncodeToString(pk.X.Bytes())
- yenc := hex.EncodeToString(pk.Y.Bytes())
- h.sm2pubkey = SM2PubKeyCombine(xenc, yenc)
- h.isSecureInit = true
- return nil
- }
- func (h *ZLLAuthHandler) GetSM2PublicKey() string {
- return h.sm2pubkey
- }
- func (h *ZLLAuthHandler) GetEncryptionInfo() (map[string]string, error) {
- if !h.isSecureInit {
- return nil, fmt.Errorf("secure module not initialized")
- }
- return map[string]string{
- "method": "sm2",
- "pubkey": h.sm2pubkey,
- "cipherMode": "C1C3C2",
- "header": "04",
- }, nil
- }
- func (h *ZLLAuthHandler) GetJwtTTL() time.Duration {
- return h.config.JWTTTL
- }
- func (h *ZLLAuthHandler) HandlingOtherEncryptedRequest(encData string, v interface{}) (visibleErr LoginFailureType, internalErr error) {
- if !h.isSecureInit {
- visibleErr = LFT_SECURE_SYSTEM_NOT_INIT
- internalErr = fmt.Errorf("secure module not initialized")
- return
- }
- hdec, err := hex.DecodeString(encData)
- if err != nil {
- visibleErr = LFT_DECODE_HEX_FAIL
- internalErr = fmt.Errorf("decode hex data error: %s", err)
- return
- }
- pt, err := sm2.Decrypt(h.sm2key, hdec)
- if err != nil {
- visibleErr = LFT_DECRYPT_SM2_FAIL
- internalErr = fmt.Errorf("decode hex data error: %s", err)
- return
- }
- err = json.Unmarshal(pt, v)
- if err != nil {
- visibleErr = LFT_UNMARSHAL_JSON_FAIL
- internalErr = fmt.Errorf("unmarshal json error: %s", err)
- return
- }
- return LFT_SUCCESS, nil
- }
- func (h *ZLLAuthHandler) HandlingLogin(data string, serverExternalInfo map[string]interface{}) (isSuccess bool, jwtdata JwtResult, visibleErr LoginFailureType, internalErr error) {
- if !h.isSecureInit {
- isSuccess = false
- jwtdata = NewEmptyJwtResult()
- visibleErr = LFT_SECURE_SYSTEM_NOT_INIT
- internalErr = fmt.Errorf("secure module not initialized")
- return
- }
- if h.config.UserCheck == nil {
- isSuccess = false
- jwtdata = NewEmptyJwtResult()
- visibleErr = LFT_NO_LOGIN_CHECK_HANDLER
- internalErr = fmt.Errorf("no login check handler specified")
- return
- }
- hdec, err := hex.DecodeString(data)
- if err != nil {
- isSuccess = false
- jwtdata = NewEmptyJwtResult()
- visibleErr = LFT_DECODE_HEX_FAIL
- internalErr = fmt.Errorf("decode hex data error: %s", err)
- return
- }
- pt, err := sm2.Decrypt(h.sm2key, hdec)
- if err != nil {
- isSuccess = false
- jwtdata = NewEmptyJwtResult()
- visibleErr = LFT_DECRYPT_SM2_FAIL
- internalErr = fmt.Errorf("decode hex data error: %s", err)
- return
- }
- var jdata map[string]interface{}
- err = json.Unmarshal(pt, &jdata)
- if err != nil {
- isSuccess = false
- jwtdata = NewEmptyJwtResult()
- visibleErr = LFT_UNMARSHAL_JSON_FAIL
- internalErr = fmt.Errorf("unmarshal json error: %s", err)
- return
- }
- suc, exi, ve, err := h.config.UserCheck.CheckUserLogin(jdata, serverExternalInfo)
- if !suc {
- isSuccess = false
- jwtdata = NewEmptyJwtResult()
- visibleErr = ve
- internalErr = fmt.Errorf("error from login check handler: %s", err)
- return
- }
- iat := time.Now().Unix()
- exp := time.Now().Add(h.config.JWTTTL).Unix()
- clm := &ZLLAuthJwtClaim{
- ExpiresAt: exp,
- IssuedAt: iat,
- Issuer: h.config.JWTIssuer,
- NotBefore: iat,
- Subject: zllauthSubject,
- ExtendInfo: exi,
- }
- if h.config.JWTJTIGenFunc != nil {
- clm.Id = h.config.JWTJTIGenFunc()
- }
- jsg := jwt.NewWithClaims(h.config.JWTSignMethod, clm)
- jr := NewEmptyJwtResult()
- jr.ExpireTime = float64(exp)
- jr.IssueTime = float64(iat)
- tok, err := jsg.SignedString(h.config.JWTPrivateKey)
- if err != nil {
- isSuccess = false
- jwtdata = NewEmptyJwtResult()
- visibleErr = LFT_JWT_SIGN_ERROR
- internalErr = fmt.Errorf("sign jwt failed: %s", err)
- return
- }
- jr.JwtStr = string(tok)
- isSuccess = true
- jwtdata = jr
- visibleErr = LFT_SUCCESS
- internalErr = nil
- return
- }
- func (h *ZLLAuthHandler) parseJwtToClaims(jwtstr string) (clm *ZLLAuthJwtClaim, err error) {
- tko, err := jwt.ParseWithClaims(jwtstr, &ZLLAuthJwtClaim{}, func(token *jwt.Token) (i interface{}, err error) {
- return h.config.JWTPublicKey, nil
- })
- if err != nil {
- return nil, fmt.Errorf("parse jwt error: %s", err)
- }
- vcast, castok := tko.Claims.(*ZLLAuthJwtClaim)
- if castok {
- vok := vcast.VerifyIssuer(h.config.JWTIssuer, true)
- if !vok {
- return nil, fmt.Errorf("issuer not match")
- }
- vok = vcast.VerifySubject(zllauthSubject, true)
- if !vok {
- return nil, fmt.Errorf("subject not match")
- }
- return vcast, nil
- } else {
- return nil, fmt.Errorf("claim type not match")
- }
- }
- func (h *ZLLAuthHandler) CheckJWT(jwtstr string) (isSuccess bool, info map[string]interface{}, visibleErr LoginFailureType, internalErr error) {
- vclm, err := h.parseJwtToClaims(jwtstr)
- if err != nil {
- isSuccess = false
- info = nil
- visibleErr = LFT_JWT_CHECK_FAIL
- internalErr = fmt.Errorf("failed check jwt: %s", err)
- return
- }
- if vclm.Issuer != h.config.JWTIssuer {
- isSuccess = false
- info = nil
- visibleErr = LFT_JWT_ISSUER_NOT_MATCH
- internalErr = fmt.Errorf("failed check jwt: issuer not match")
- return
- }
- if vclm.Subject != "zllauth1-auth" {
- isSuccess = false
- info = nil
- visibleErr = LFT_JWT_SUBJECT_NOT_MATCH
- internalErr = fmt.Errorf("failed check jwt: subject not match")
- return
- }
- isSuccess = true
- info = vclm.ExtendInfo
- visibleErr = LFT_SUCCESS
- internalErr = nil
- return
- }
- func (h *ZLLAuthHandler) RenewJWT(jwtstr string) (isSuccess bool, jwtdata JwtResult, visibleErr LoginFailureType, internalErr error) {
- se, exi, ve, err := h.CheckJWT(jwtstr)
- if !se {
- isSuccess = false
- jwtdata = NewEmptyJwtResult()
- ve = ve
- internalErr = err
- return
- }
- err = h.config.UserCheck.RenewJwtCallback(exi)
- if err != nil {
- isSuccess = false
- jwtdata = NewEmptyJwtResult()
- ve = LFT_JWT_RENEW_CALLBACK_ERROR
- internalErr = err
- return
- }
- iat := time.Now().Unix()
- exp := time.Now().Add(h.config.JWTTTL).Unix()
- clm := &ZLLAuthJwtClaim{
- ExpiresAt: exp,
- IssuedAt: iat,
- Issuer: h.config.JWTIssuer,
- NotBefore: iat,
- Subject: zllauthSubject,
- ExtendInfo: exi,
- }
- if h.config.JWTJTIGenFunc != nil {
- clm.Id = h.config.JWTJTIGenFunc()
- }
- jsg := jwt.NewWithClaims(h.config.JWTSignMethod, clm)
- jr := NewEmptyJwtResult()
- jr.ExpireTime = float64(exp)
- jr.IssueTime = float64(iat)
- tok, err := jsg.SignedString(h.config.JWTPrivateKey)
- if err != nil {
- isSuccess = false
- jwtdata = NewEmptyJwtResult()
- visibleErr = LFT_JWT_SIGN_ERROR
- internalErr = fmt.Errorf("sign jwt failed: %s", err)
- return
- }
- jr.JwtStr = string(tok)
- isSuccess = true
- jwtdata = jr
- visibleErr = LFT_SUCCESS
- internalErr = nil
- return
- }
|