src.dualinventive.com/go/mtinfo-go/authgrpc.go

180 lines
4.5 KiB
Go

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
}