-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.go
139 lines (114 loc) · 3.04 KB
/
server.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package main
import (
"github.com/clawio/service-auth/lib"
pb "github.com/clawio/service-auth/proto"
"github.com/dgrijalva/jwt-go"
_ "github.com/go-sql-driver/mysql"
"github.com/jinzhu/gorm"
_ "github.com/lib/pq"
_ "github.com/mattn/go-sqlite3"
rus "github.com/sirupsen/logrus"
"golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"time"
)
const (
dirPerm = 0755
)
// debugLogger satisfies Gorm's logger interface
// so that we can log SQL queries at Logrus' debug level
type debugLogger struct{}
func (*debugLogger) Print(msg ...interface{}) {
rus.Debug(msg)
}
type newServerParams struct {
dsn string
driver string
sharedSecret string
signMethod string
maxSqlIdle int
maxSqlConcurrency int
}
func newServer(p *newServerParams) (*server, error) {
db, err := newDB(p.driver, p.dsn)
if err != nil {
rus.Error(err)
return nil, err
}
db.LogMode(true)
db.SetLogger(&debugLogger{})
db.DB().SetMaxIdleConns(p.maxSqlIdle)
db.DB().SetMaxOpenConns(p.maxSqlConcurrency)
err = db.AutoMigrate(&identityRecord{}).Error
if err != nil {
rus.Error(err)
return nil, err
}
rus.Infof("automigration applied")
s := &server{}
s.p = p
s.db = db
return s, nil
}
type server struct {
p *newServerParams
db *gorm.DB
}
func (s *server) Authenticate(ctx context.Context, r *pb.AuthRequest) (*pb.AuthResponse, error) {
traceID, err := getGRPCTraceID(ctx)
if err != nil {
rus.Error("cannot get trace ID")
return &pb.AuthResponse{}, err
}
log := rus.WithField("trace", traceID).WithField("svc", serviceID)
ctx = newGRPCTraceContext(ctx, traceID)
log.Info("request started")
// Time request
reqStart := time.Now()
defer func() {
// Compute request duration
reqDur := time.Since(reqStart)
// Log access info
log.WithFields(rus.Fields{
"method": "authenticate",
"type": "grpcaccess",
"duration": reqDur.Seconds(),
}).Info("request finished")
}()
rec := &identityRecord{}
err = s.db.Where("pid=? AND password=?", r.Username, r.Password).First(rec).Error
if err != nil {
log.Error(err)
return &pb.AuthResponse{}, grpc.Errorf(codes.Unauthenticated, "%s not found", r.Username)
}
idt := &lib.Identity{}
idt.Pid = rec.Pid
idt.Idp = rec.Idp
idt.Email = rec.Email
idt.DisplayName = rec.DisplayName
token, err := s.createToken(idt)
if err != nil {
log.Error(err)
return &pb.AuthResponse{}, err
}
res := &pb.AuthResponse{}
res.Token = token
log.Infof("authentication successful for %s", idt)
return res, nil
}
// It returns the JWT token or an error.
func (s *server) createToken(idt *lib.Identity) (string, error) {
token := jwt.New(jwt.GetSigningMethod(s.p.signMethod))
token.Claims["pid"] = idt.Pid
token.Claims["idp"] = idt.Idp
token.Claims["display_name"] = idt.DisplayName
token.Claims["email"] = idt.Email
token.Claims["iss"] = "localhost"
token.Claims["exp"] = time.Now().Add(time.Second * 3600).UnixNano()
tokenStr, err := token.SignedString([]byte(s.p.sharedSecret))
if err != nil {
return "", err
}
return tokenStr, nil
}