package mtinfo import ( "context" "crypto/rsa" "errors" "fmt" "github.com/dgrijalva/jwt-go.git" "google.golang.org/grpc" "google.golang.org/grpc/metadata" auth "src.dualinventive.com/go/authentication-service/grpc" ) //grpcAuthServiceClient contains authentication related operations over GRPC type grpcAuthServiceClient struct { client auth.AuthenticationServiceClient publicKey *rsa.PublicKey userAgent string } func (as *grpcAuthServiceClient) Login(username, companyCode, password string) (string, error) { ctx := as.withContext("") in := &auth.LoginRequest{Credentials: &auth.Credentials{ Username: username, CompanyCode: companyCode, Password: password, }} resp, err := as.client.Login(ctx, in) if err != nil { return "", err } return resp.Token.Secret, nil } func (as *grpcAuthServiceClient) Logout(token string) error { ctx := as.withContext(token) in := &auth.Empty{} _, err := as.client.Logout(ctx, in) return err } func (as *grpcAuthServiceClient) Me(token string) (*User, error) { ctx := as.withContext(token) in := &auth.Empty{} resp, err := as.client.Me(ctx, in) if err != nil { return nil, err } user := newUser(resp.User) return &user, nil } func (as *grpcAuthServiceClient) RequestPasswordReset(username string) error { in := &auth.RequestPasswordResetRequest{ UserName: username, } _, err := as.client.RequestPasswordReset(context.Background(), in) return err } func (as *grpcAuthServiceClient) RedeemPasswordReset(username, resetCode, password, passwordVerify string) error { in := &auth.RedeemPasswordResetRequest{ UserName: username, ResetCode: resetCode, Password: password, PasswordVerify: passwordVerify, } _, err := as.client.RedeemPasswordReset(context.Background(), in) return err } func (as *grpcAuthServiceClient) ListTokens(token string) (OpaqueTokens, error) { ctx := as.withContext(token) in := &auth.Empty{} resp, err := as.client.ListTokens(ctx, in) if err != nil { return nil, err } return newOpaqueTokens(resp.Tokens), nil } func (as *grpcAuthServiceClient) DeleteToken(token string, opaqueToken string) error { ctx := as.withContext(token) in := &auth.DeleteTokenRequest{ OpaqueId: opaqueToken, } _, err := as.client.DeleteToken(ctx, in) return err } //VerifyToken verifies the given token to see if its valid. //When a public key is configured, token is locally verified using JWT. //When no public key is configured, token is remotely verified using GRPC. //Returns false when token signed portion is invalid, or token is expired. func (as *grpcAuthServiceClient) VerifyToken(token string, rights ...string) (bool, error) { if as.publicKey != nil { var claims Claims tkn, err := jwt.ParseWithClaims(token, &claims, func(token *jwt.Token) (interface{}, error) { return as.publicKey, nil }) if err != nil { return false, fmt.Errorf("error parsing jwt token: %s", err.Error()) } return tkn.Valid && claims.Rights.containsAll(rights...), nil } return as.VerifyTokenRemotely(token, rights...) } //VerifyTokenRemotely verifies the given token to see if its valid. //Token is remotely verified using GRPC. //Returns false when token signed portion is invalid, or token is expired. func (as *grpcAuthServiceClient) VerifyTokenRemotely(token string, rights ...string) (bool, error) { ctx := as.withContext(token) in := &auth.VerifyTokenRequest{Rights: rights} resp, err := as.client.VerifyToken(ctx, in) if err != nil { return false, err } return resp.Valid, nil } func (as *grpcAuthServiceClient) UserAgent() string { return as.userAgent } func (as *grpcAuthServiceClient) SetUserAgent(userAgent string) { as.userAgent = userAgent } func (as *grpcAuthServiceClient) withContext(token string) context.Context { md := metadata.Pairs( "token", token, "userAgent", as.userAgent, ) ctx := metadata.NewOutgoingContext(context.Background(), md) return ctx } func newGrpcAuthServiceClient(host, port string, publicKeyPath string) (AuthServiceClient, error) { client := &grpcAuthServiceClient{ userAgent: "grpc", } if host == "" { return nil, errors.New("host not configured") } if port == "" { return nil, errors.New("port not configured") } if publicKeyPath != "" { publicKey, err := configurePublicKey(publicKeyPath) if err != nil { return nil, fmt.Errorf("invalid public key: %s", err.Error()) } client.publicKey = publicKey } conn, err := grpc.Dial(fmt.Sprintf("%s:%s", host, port), grpc.WithInsecure()) if err != nil { return nil, err } client.client = auth.NewAuthenticationServiceClient(conn) return client, nil }