From 1f9eb75e41a975df2f2ae72bc16dcf68505bda81 Mon Sep 17 00:00:00 2001 From: mountain Date: Wed, 13 Aug 2025 22:06:06 +0900 Subject: [PATCH] =?UTF-8?q?osg=20VerifyJWT=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- opensearch/client.go | 44 ++++++++++++++++++++++++++++++++++++++ opensearch/client_test.go | 45 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) diff --git a/opensearch/client.go b/opensearch/client.go index d6058d0..2b0d1d4 100644 --- a/opensearch/client.go +++ b/opensearch/client.go @@ -9,6 +9,7 @@ import ( "encoding/json" "fmt" "net/http" + "slices" "strings" "sync/atomic" "time" @@ -155,6 +156,49 @@ func (c *Client) MakeJWT(subject string, role string, ttl time.Duration) string return encoded + "." + string(sigenc) } +func (c *Client) VerifyJWT(token string) (subject string, role string) { + dot := strings.LastIndex(token, ".") + if dot < 0 { + return + } + + encoded := token[:dot] + sigenc := token[dot+1:] + signature := make([]byte, encoding.DecodedLen(len(sigenc))) + encoding.Decode(signature, []byte(sigenc)) + + mac := hmac.New(sha256.New, c.signingKey) + mac.Write([]byte(encoded)) + calsig := mac.Sum(nil) + if slices.Compare(calsig, signature) != 0 { + return + } + + _, payload, ok := strings.Cut(encoded, ".") + if !ok { + return + } + + srcjson, err := encoding.DecodeString(payload) + if err != nil { + return + } + + var src struct { + Exp int64 `json:"exp"` + Sub string `json:"sub"` + Roles string `json:"roles"` + } + if json.Unmarshal([]byte(srcjson), &src) != nil { + return + } + if src.Exp < time.Now().Unix() { + return + } + + return src.Sub, src.Roles +} + func NewClient(cfg Config) (Client, error) { if len(cfg.Addresses) == 0 { return Client{}, nil diff --git a/opensearch/client_test.go b/opensearch/client_test.go index 8ef76b5..4a70680 100644 --- a/opensearch/client_test.go +++ b/opensearch/client_test.go @@ -1,7 +1,11 @@ package opensearch import ( + "encoding/base64" "testing" + "time" + + "go.mongodb.org/mongo-driver/bson/primitive" ) func TestNewClient(t *testing.T) { @@ -31,3 +35,44 @@ func TestNewClient(t *testing.T) { // time.Sleep(time.Second) // } } + +func TestClient_MakeJWT(t *testing.T) { + sk := "UGdiOTdLVjFBTWtndTRNRiZmVjdwMDdCRW1lSSUxTnA=" + dst := make([]byte, len(sk)*2) + dstlen, _ := base64.StdEncoding.Decode(dst, []byte(sk)) + signingKey := dst[:dstlen] + uid := primitive.NewObjectID().Hex() + + type args struct { + subject string + role string + ttl time.Duration + } + tests := []struct { + name string + c *Client + args args + want string + }{ + // TODO: Add test cases. + { + c: &Client{ + signingKey: signingKey, + }, + args: args{ + subject: uid, + role: "ds_client", + ttl: time.Minute, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := tt.c.MakeJWT(tt.args.subject, tt.args.role, tt.args.ttl) + subj, role := tt.c.VerifyJWT(got) + if subj != tt.args.subject || role != tt.args.role { + t.Errorf("Client.MakeJWT() = %v, %v, want %v, %v", subj, role, tt.args.subject, tt.args.role) + } + }) + } +}