pomerium/proxy/authenticator/grpc.go
2019-02-11 20:15:01 -08:00

98 lines
3 KiB
Go

package authenticator // import "github.com/pomerium/pomerium/proxy/authenticator"
import (
"context"
"errors"
"time"
"github.com/golang/protobuf/ptypes"
"google.golang.org/grpc"
pb "github.com/pomerium/pomerium/proto/authenticate"
)
// RedeemResponse contains data from a authenticator redeem request.
type RedeemResponse struct {
AccessToken string
RefreshToken string
IDToken string
User string
Email string
Expiry time.Time
}
// AuthenticateGRPC is a gRPC implementation of an authenticator (authenticate client)
type AuthenticateGRPC struct {
conn *grpc.ClientConn
client pb.AuthenticatorClient
}
// Redeem makes an RPC call to the authenticate service to creates a session state
// from an encrypted code provided as a result of an oauth2 callback process.
func (a *AuthenticateGRPC) Redeem(code string) (*RedeemResponse, error) {
if code == "" {
return nil, errors.New("missing code")
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
r, err := a.client.Authenticate(ctx, &pb.AuthenticateRequest{Code: code})
if err != nil {
return nil, err
}
expiry, err := ptypes.Timestamp(r.Expiry)
if err != nil {
return nil, err
}
return &RedeemResponse{
AccessToken: r.AccessToken,
RefreshToken: r.RefreshToken,
IDToken: r.IdToken,
User: r.User,
Email: r.Email,
Expiry: expiry,
// RefreshDeadline: (expiry).Truncate(time.Second),
// LifetimeDeadline: extendDeadline(p.CookieLifetimeTTL),
// ValidDeadline: extendDeadline(p.CookieExpire),
}, nil
}
// Refresh makes an RPC call to the authenticate service to attempt to refresh the
// user's session. Requires a valid refresh token. Will return an error if the identity provider
// has revoked the session or if the refresh token is no longer valid in this context.
func (a *AuthenticateGRPC) Refresh(refreshToken string) (string, time.Time, error) {
if refreshToken == "" {
return "", time.Time{}, errors.New("missing refresh token")
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
r, err := a.client.Refresh(ctx, &pb.RefreshRequest{RefreshToken: refreshToken})
if err != nil {
return "", time.Time{}, err
}
expiry, err := ptypes.Timestamp(r.Expiry)
if err != nil {
return "", time.Time{}, err
}
return r.AccessToken, expiry, nil
}
// Validate makes an RPC call to the authenticate service to validate the JWT id token;
// does NOT do nonce or revokation validation.
// https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation
func (a *AuthenticateGRPC) Validate(idToken string) (bool, error) {
if idToken == "" {
return false, errors.New("missing id token")
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
r, err := a.client.Validate(ctx, &pb.ValidateRequest{IdToken: idToken})
if err != nil {
return false, err
}
return r.IsValid, nil
}
// Close tears down the ClientConn and all underlying connections.
func (a *AuthenticateGRPC) Close() error {
return a.conn.Close()
}