BIg commit to make it actualy working

main
René Jochum 2 years ago
parent 1ecc9bd640
commit c5d9147ff7
Signed by: jochum
GPG Key ID: F7D906F5E51E8E5E

@ -0,0 +1,35 @@
##########################################################
# Build
##########################################################
DOCKER_IO=docker.io
DOCKER_ORG_JO_MICRO=docker.io/jomicro
BUILD_MOUNT_FOLDER="~"
##########################################################
# Testing
##########################################################
## Micro communication
MICRO_TRANSPORT=grpc
MICRO_REGISTRY=nats
MICRO_REGISTRY_ADDRESS=localhost:4222
MICRO_BROKER=nats
MICRO_BROKER_ADDRESS=localhost:4222
## Log
MICRO_AUTH2_LOG_LEVEL=trace
## Database
MICRO_AUTH2_DATABASE_DEBUG=true
MICRO_AUTH2_DATABASE_URL="postgres://postgres:redacted@localhost:5432/auth?sslmode=disable"
MICRO_AUTH2_MIGRATIONS_DIR="./cmd/microauth2sqld/migrations"
## JWT
MICRO_AUTH2_JWT_AUDIENCE="https://lobby.wz2100.net,https://wz2100.net"
# go.micro.auth Ed25519 JWT keys in PEM - generated using '/tmp/go-build3574312808/b001/exe/microauth2sqld --auth2_generate_keys'
MICRO_AUTH2_JWT_PRIV_KEY="LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1DNENBUUF3QlFZREsyVndCQ0lFSUcwQkt3elV6bnRMQXR2K1Ztb0xsYVV5ZlJBdm04SVpiY2dUMC9BZGdyekIKLS0tLS1FTkQgUFJJVkFURSBLRVktLS0tLQo="
MICRO_AUTH2_JWT_PUB_KEY="LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUNvd0JRWURLMlZ3QXlFQXB6V0Q5T29iWUUrMEYxbnI0MWlKL0VITC9veDZDT1NTeGlwZjh6c21IQlU9Ci0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQo="
MICRO_AUTH2_JWT_REFRESH_PRIV_KEY="LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1DNENBUUF3QlFZREsyVndCQ0lFSUJTVE1YTDVvUGxXWFg1azl6akpvWVVFdTJYWndkbjBvVWJRdjd6eHJIa3YKLS0tLS1FTkQgUFJJVkFURSBLRVktLS0tLQo="
MICRO_AUTH2_JWT_REFRESH_PUB_KEY="LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUNvd0JRWURLMlZ3QXlFQVRaWG4xWkt1Z3puTGVQdHNHUFFhbTVVS2d3K0ZCMGxudUxZYllQUnRxb1k9Ci0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQo="

2
.gitignore vendored

@ -1,3 +1,5 @@
.env
.DS_STORE
.task/

@ -1,5 +1,7 @@
version: '3'
dotenv: [".env"]
vars:
GIT_TAG:
sh: git tag --points-at HEAD
@ -25,21 +27,29 @@ tasks:
volume:
run: "once"
cmds:
- podman volume inspect jo-micro_auth_go 1>/dev/null 2>&1 || podman volume create jo-micro_auth_go
- podman volume inspect jo-micro_auth2_go 1>/dev/null 2>&1 || podman volume create jo-micro_auth2_go
builder:
desc: Run something in the builder container for example "task builder -- go get -u ./..."
cmds:
- podman run --rm -v "{{.VOLUME_PATH}}:/go:rw" -v "$PWD:/code" registry.fk.jochum.dev/jo-micro/builder:latest {{.CLI_ARGS}}
- podman run --rm
-v "{{.BUILD_MOUNT_FOLDER_INT}}:{{.BUILD_MOUNT_FOLDER_INT}}"
-v "{{.PWD}}:/code"
-v "{{.VOLUME_PATH}}:/go:rw"
{{.DOCKER_ORG_JO_MICRO}}/builder:latest {{.CLI_ARGS}}
vars:
VOLUME_PATH:
sh: podman volume inspect jo-micro_auth_go --format "{{"{{"}}.Mountpoint{{"}}"}}"
sh: podman volume inspect jo-micro_auth2_go --format "{{"{{"}}.Mountpoint{{"}}"}}"
BUILD_MOUNT_FOLDER_INT:
sh: realpath {{.BUILD_MOUNT_FOLDER}}
preconditions:
- test -n "{{.CLI_ARGS}}"
protoc:
run: "once"
desc: Generate protobruf go files
sources:
- ./proto/**/*.proto
- ./internal/proto/**/*.proto
cmds:
- task: builder
vars:
@ -51,16 +61,26 @@ tasks:
sources:
- ./go.sum
- ./*.go
- ./service/microauthsqld/**/*.go
- ./service/microauth2sqld/**/*.go
- ./internal/**/*.go
cmds:
- podman build -v "{{.VOLUME_PATH}}:/go:rw" --build-arg VERSION={{.VERSION}} -t registry.fk.jochum.dev/jo-micro/auth2-sql:latest -f ./docker/microauthsqld/Dockerfile .
- podman build
-v "{{.BUILD_MOUNT_FOLDER_INT}}:{{.BUILD_MOUNT_FOLDER_INT}}"
-v "{{.VOLUME_PATH}}:/go:rw"
--build-arg VERSION={{.VERSION}}
--build-arg=DOCKER_IO={{.DOCKER_IO}}
--build-arg=DOCKER_ORG_JO_MICRO={{.DOCKER_ORG_JO_MICRO}}
-t {{.DOCKER_ORG_JO_MICRO}}/auth2-sql:latest
-f ./docker/microauth2sqld/Dockerfile
.
vars:
VOLUME_PATH:
sh: podman volume inspect jo-micro_auth_go --format "{{"{{"}}.Mountpoint{{"}}"}}"
sh: podman volume inspect jo-micro_auth2_go --format "{{"{{"}}.Mountpoint{{"}}"}}"
BUILD_MOUNT_FOLDER_INT:
sh: realpath {{.BUILD_MOUNT_FOLDER}}
podman:
desc: Generate docker container for jo-micro/auth-sql tagged as registry.fk.jochum.dev/jo-micro/auth2-sql:latest
desc: Generate docker container for jo-micro/auth-sql tagged as {{.DOCKER_ORG_JO_MICRO}}/auth2-sql:latest
cmds:
- task: build:authsql
@ -88,11 +108,11 @@ tasks:
keys:
desc: Generate keys
cmds:
- podman run registry.fk.jochum.dev/jo-micro/auth2-sql:latest microauthsqld --generate-keys
- podman run {{.DOCKER_ORG_JO_MICRO}}/auth2-sql:latest microauth2sqld --auth2_generate_keys
rm:
desc: Remove all persistent data
cmds:
- podman volume rm jo-micro_auth_go || exit 0
- podman image rm registry.fk.jochum.dev/jo-micro/auth2-sql:latest || exit 0
- podman volume rm jo-micro_auth2_go || exit 0
- podman image rm {{.DOCKER_ORG_JO_MICRO}}/auth2-sql:latest || exit 0
- rm -rf $PWD/.task

@ -0,0 +1,10 @@
package config
var (
Version = "0.0.1-dev0"
)
const (
Name = "go.micro.auth"
PkgPath = "jochum.dev/jo-micro/auth2"
)

@ -0,0 +1,18 @@
package db
import (
"context"
"fmt"
"jochum.dev/jo-micro/auth2/internal/ibun"
)
func RoleGetId(ctx context.Context, name string) (string, error) {
var result string
err := ibun.Bun.NewSelect().Table("roles").Column("id").Limit(1).Where("name = ?", name).Scan(ctx, &result)
if err != nil || len(result) < 1 {
return "", fmt.Errorf("role '%s' not found", name)
}
return result, nil
}

@ -0,0 +1,160 @@
package db
import (
"context"
"time"
"github.com/google/uuid"
"github.com/uptrace/bun"
"jochum.dev/jo-micro/auth2/internal/ibun"
)
type User struct {
bun.BaseModel `bun:"users,alias:u"`
ID uuid.UUID `bun:"id,pk,type:uuid,default:uuid_generate_v4()" json:"id" yaml:"id"`
Username string `bun:"username" json:"username" yaml:"username"`
Password string `bun:"password" json:"-" yaml:"-"`
Email string `bun:"email" json:"email" yaml:"email"`
Roles []string `bun:",array,scanonly" json:"roles" yaml:"roles"`
// Timestamps
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at" yaml:"created_at"`
UpdatedAt bun.NullTime `bun:"updated_at" json:"updated_at" yaml:"updated_at"`
// SoftDelete
DeletedAt bun.NullTime `bun:"deleted_at,soft_delete,nullzero" json:"deleted_at" yaml:"deleted_at"`
}
func UserList(ctx context.Context, limit, offset uint64) ([]User, error) {
// Get the data from the db.
var users []User
err := ibun.Bun.NewSelect().
Model(&users).
ColumnExpr("u.*").
ColumnExpr("array(SELECT r.name FROM users_roles AS ur LEFT JOIN roles AS r ON ur.role_id = r.id WHERE ur.user_id = u.id) AS roles").
Limit(int(limit)).
Offset(int(offset)).Scan(ctx)
if err != nil {
return nil, err
}
return users, nil
}
func UserDetail(ctx context.Context, id string) (*User, error) {
user := User{}
err := ibun.Bun.NewSelect().
Model(&user).
ColumnExpr("u.*").
ColumnExpr("array(SELECT r.name FROM users_roles AS ur LEFT JOIN roles AS r ON ur.role_id = r.id WHERE ur.user_id = u.id) AS roles").
Limit(1).
Where("id = ?", id).
Scan(ctx)
if err != nil {
return nil, err
}
return &user, nil
}
func UserDelete(ctx context.Context, id string) error {
user := User{}
_, err := ibun.Bun.NewDelete().Model(&user).Where("id = ?", id).Exec(ctx)
return err
}
func UserUpdateRoles(ctx context.Context, id string, roles []string) (*User, error) {
// Check if all new roles exists
rolesIds := make([]string, len(roles))
for idx, role := range roles {
id, err := RoleGetId(ctx, role)
if err != nil {
return nil, err
}
rolesIds[idx] = id
}
// Delete all current roles
_, err := ibun.Bun.NewDelete().Table("users_roles").Where("user_id = ?", id).Exec(ctx)
if err != nil {
return nil, err
}
// Exit out if user wants to delete all roles
if len(roles) < 1 {
return UserDetail(ctx, id)
}
// Reassign roles
for _, roleId := range rolesIds {
values := map[string]interface{}{
"user_id": id,
"role_id": roleId,
}
_, err = ibun.Bun.NewInsert().Model(&values).TableExpr("users_roles").Exec(ctx)
if err != nil {
return nil, err
}
}
return UserDetail(ctx, id)
}
func UserFindByUsername(ctx context.Context, username string) (*User, error) {
user := User{}
err := ibun.Bun.NewSelect().
Model(&user).
ColumnExpr("u.*").
ColumnExpr("array(SELECT r.name FROM users_roles AS ur LEFT JOIN roles AS r ON ur.role_id = r.id WHERE ur.user_id = u.id) AS roles").
Limit(1).
Where("u.username = ?", username).
Scan(ctx)
if err != nil {
return nil, err
}
return &user, nil
}
func UserFindById(ctx context.Context, id string) (*User, error) {
user := User{}
err := ibun.Bun.NewSelect().
Model(&user).
ColumnExpr("u.*").
ColumnExpr("array(SELECT r.name FROM users_roles AS ur LEFT JOIN roles AS r ON ur.role_id = r.id WHERE ur.user_id = u.id) AS roles").
Limit(1).
Where("u.id = ?", id).
Scan(ctx)
if err != nil {
return nil, err
}
return &user, nil
}
func UserCreate(ctx context.Context, username, password, email string, roles []string) (*User, error) {
// Create the user
user := User{}
user.Username = username
user.Password = password
user.Email = email
_, err := ibun.Bun.NewInsert().Model(&user).Exec(ctx, &user)
if err != nil {
return nil, err
}
// Create roles
_, err = UserUpdateRoles(ctx, user.ID.String(), roles)
if err != nil {
if len(user.ID.String()) > 0 {
UserDelete(ctx, user.ID.String())
}
return nil, err
}
return &user, nil
}

@ -0,0 +1,278 @@
package handler
import (
"context"
"crypto/ed25519"
"crypto/rsa"
"fmt"
"net/http"
"time"
"github.com/golang-jwt/jwt/v4"
"go-micro.dev/v4/errors"
"go-micro.dev/v4/util/log"
"google.golang.org/protobuf/types/known/emptypb"
"jochum.dev/jo-micro/auth2"
"jochum.dev/jo-micro/auth2/cmd/microauth2sqld/config"
"jochum.dev/jo-micro/auth2/cmd/microauth2sqld/db"
"jochum.dev/jo-micro/auth2/internal/argon2"
"jochum.dev/jo-micro/auth2/internal/proto/authpb"
"jochum.dev/jo-micro/auth2/shared/sjwt"
)
type InitConfig struct {
Audiences []string
RefreshTokenExpiry int64
AccessTokenExpiry int64
AccessTokenPubKey string
AccessTokenPrivKey string
RefreshTokenPubKey string
RefreshTokenPrivKey string
}
type Handler struct {
audiences []string
refreshTokenExpiry int64
accessTokenExpiry int64
accessTokenPubKey any
accessTokenPrivKey any
refreshTokenPubKey any
refreshTokenPrivKey any
}
func NewHandler() *Handler {
return &Handler{}
}
func (h *Handler) Init(c InitConfig) error {
h.audiences = c.Audiences
h.accessTokenExpiry = c.AccessTokenExpiry
h.refreshTokenExpiry = c.RefreshTokenExpiry
pub, priv, err := sjwt.DecodeKeyPair(c.AccessTokenPubKey, c.AccessTokenPrivKey)
if err != nil {
return err
}
h.accessTokenPubKey = pub
h.accessTokenPrivKey = priv
pub, priv, err = sjwt.DecodeKeyPair(c.RefreshTokenPubKey, c.RefreshTokenPrivKey)
if err != nil {
return err
}
h.refreshTokenPubKey = pub
h.refreshTokenPrivKey = priv
return nil
}
func (h *Handler) Stop() error {
return nil
}
func (s *Handler) List(ctx context.Context, in *authpb.ListRequest, out *authpb.UserListReply) error {
results, err := db.UserList(ctx, in.Limit, in.Offset)
if err != nil {
return err
}
// Copy the data to the result
for _, result := range results {
out.Data = append(out.Data, &authpb.User{
Id: result.ID.String(),
Username: result.Username,
Email: result.Email,
})
}
return nil
}
func (s *Handler) Detail(ctx context.Context, in *authpb.UserIDRequest, out *authpb.User) error {
result, err := db.UserDetail(ctx, in.UserId)
if err != nil {
return err
}
out.Id = result.ID.String()
out.Email = result.Email
out.Username = result.Username
out.Roles = result.Roles
return nil
}
func (s *Handler) Delete(ctx context.Context, in *authpb.UserIDRequest, out *emptypb.Empty) error {
err := db.UserDelete(ctx, in.UserId)
if err != nil {
return err
}
return nil
}
func (s *Handler) UpdateRoles(ctx context.Context, in *authpb.UpdateRolesRequest, out *authpb.User) error {
result, err := db.UserUpdateRoles(ctx, in.UserId, in.Roles)
if err != nil {
return err
}
out.Id = result.ID.String()
out.Email = result.Email
out.Username = result.Username
out.Roles = result.Roles
return nil
}
func (s *Handler) Register(ctx context.Context, in *authpb.RegisterRequest, out *authpb.User) error {
if in.Username == auth2.ROLE_SERVICE {
return errors.New(config.Name, "User already exists", http.StatusConflict)
}
hash, err := argon2.Hash(in.Password, argon2.DefaultParams)
if err != nil {
return err
}
result, err := db.UserCreate(ctx, in.Username, hash, in.Email, []string{auth2.ROLE_USER})
if err != nil {
return errors.New(config.Name, "User already exists", http.StatusConflict)
}
out.Id = result.ID.String()
out.Email = result.Email
out.Username = result.Username
out.Roles = result.Roles
return nil
}
func (s *Handler) genTokens(ctx context.Context, user *db.User, out *authpb.Token) error {
// Create the Claims
refreshClaims := sjwt.JWTClaims{
RegisteredClaims: &jwt.RegisteredClaims{
Issuer: config.Name,
Subject: user.Username,
Audience: s.audiences,
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Duration(s.accessTokenExpiry) * time.Second)),
NotBefore: jwt.NewNumericDate(time.Now()),
IssuedAt: jwt.NewNumericDate(time.Now()),
ID: user.ID.String(),
},
}
if err := refreshClaims.Valid(); err != nil {
return err
}
var (
accessToken *jwt.Token
refreshToken *jwt.Token
)
switch s.refreshTokenPrivKey.(type) {
case *rsa.PrivateKey:
refreshToken = jwt.NewWithClaims(jwt.SigningMethodRS512, refreshClaims)
case ed25519.PrivateKey:
refreshToken = jwt.NewWithClaims(jwt.SigningMethodEdDSA, refreshClaims)
}
refreshSignedToken, err := refreshToken.SignedString(s.refreshTokenPrivKey)
if err != nil {
return err
}
// Create the AccessToken
accessClaims := sjwt.JWTClaims{
RegisteredClaims: &jwt.RegisteredClaims{
Issuer: config.Name,
Subject: user.Username,
Audience: s.audiences,
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Duration(s.accessTokenExpiry) * time.Second)),
NotBefore: jwt.NewNumericDate(time.Now()),
IssuedAt: jwt.NewNumericDate(time.Now()),
ID: user.ID.String(),
},
Roles: user.Roles,
}
if err := accessClaims.Valid(); err != nil {
return err
}
switch s.accessTokenPrivKey.(type) {
case *rsa.PrivateKey:
accessToken = jwt.NewWithClaims(jwt.SigningMethodRS512, accessClaims)
case ed25519.PrivateKey:
accessToken = jwt.NewWithClaims(jwt.SigningMethodEdDSA, accessClaims)
}
accessSignedToken, err := accessToken.SignedString(s.accessTokenPrivKey)
if err != nil {
return err
}
out.RefreshToken = refreshSignedToken
out.RefreshTokenExpiresAt = refreshClaims.ExpiresAt.Unix()
out.AccessToken = accessSignedToken
out.AccessTokenExpiresAt = accessClaims.ExpiresAt.Unix()
return nil
}
func (s *Handler) Login(ctx context.Context, in *authpb.LoginRequest, out *authpb.Token) error {
user, err := db.UserFindByUsername(ctx, in.Username)
if err != nil {
log.Error(err)
return errors.New(config.Name, "Wrong username or password", http.StatusUnauthorized)
}
ok, err := argon2.Verify(in.Password, user.Password)
if err != nil {
return err
}
if !ok {
return errors.New(config.Name, "Wrong username or password", http.StatusUnauthorized)
}
return s.genTokens(ctx, user, out)
}
func (s *Handler) Refresh(ctx context.Context, in *authpb.RefreshTokenRequest, out *authpb.Token) error {
claims := sjwt.JWTClaims{}
_, err := jwt.ParseWithClaims(in.RefreshToken, &claims, func(token *jwt.Token) (interface{}, error) {
return s.refreshTokenPubKey, nil
})
if err != nil {
return errors.New(config.Name, fmt.Sprintf("checking the RefreshToken: %s", err), http.StatusBadRequest)
}
// Check claims (expiration)
if err = claims.Valid(); err != nil {
return fmt.Errorf("claims invalid: %s", err)
}
user, err := db.UserFindById(ctx, claims.ID)
if err != nil {
return errors.New(config.Name, fmt.Sprintf("error fetching the user: %s", err), http.StatusUnauthorized)
}
return s.genTokens(ctx, user, out)
}
func (s *Handler) Inspect(ctx context.Context, in *emptypb.Empty, out *authpb.JWTClaims) error {
u := ctx.Value("user")
if u == nil {
return errors.BadRequest("auth2/handler.Inspect|no user", "no user found in context")
}
u2 := u.(auth2.User)
out.Id = u2.Id
out.Type = u2.Type
out.Issuer = u2.Issuer
out.Metadata = u2.Metadata
out.Roles = u2.Roles
out.Scopes = u2.Scopes
return nil
}

@ -0,0 +1,353 @@
package main
import (
"crypto/ed25519"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"errors"
"fmt"
"os"
"os/exec"
"strings"
"github.com/urfave/cli/v2"
"go-micro.dev/v4"
"go-micro.dev/v4/logger"
"jochum.dev/jo-micro/auth2"
"jochum.dev/jo-micro/auth2/cmd/microauth2sqld/config"
"jochum.dev/jo-micro/auth2/cmd/microauth2sqld/handler"
"jochum.dev/jo-micro/auth2/internal/ibun"
"jochum.dev/jo-micro/auth2/internal/ilogger"
"jochum.dev/jo-micro/auth2/internal/proto/authpb"
"jochum.dev/jo-micro/router"
_ "jochum.dev/jo-micro/auth2/plugins/client/jwt"
"jochum.dev/jo-micro/auth2/plugins/verifier/endpointroles"
)
var (
ErrorNoKeys = errors.New("config MICRO_AUTH2_JWT_*_KEY or MICRO_AUTH2_JWT_REFRESH_*_KEY not given")
)
func generateEd25519PEMKeyPair() (string, string, error) {
pubKey, privKey, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
return "", "", err
}
privPKCS8, err := x509.MarshalPKCS8PrivateKey(privKey)
if err != nil {
return "", "", err
}
privPem := pem.EncodeToMemory(&pem.Block{
Type: "PRIVATE KEY",
Bytes: privPKCS8,
})
pubPKCS8, err := x509.MarshalPKIXPublicKey(pubKey)
if err != nil {
return "", "", err
}
pubPem := pem.EncodeToMemory(&pem.Block{
Type: "PUBLIC KEY",
Bytes: pubPKCS8,
})
return base64.StdEncoding.EncodeToString(pubPem), base64.StdEncoding.EncodeToString(privPem), nil
}
func generateRSAPEMKeyPair(bits int) (string, string, error) {
privKey, err := rsa.GenerateKey(rand.Reader, bits)
if err != nil {
return "", "", err
}
privPKCS8, err := x509.MarshalPKCS8PrivateKey(privKey)
if err != nil {
return "", "", err
}
privPem := pem.EncodeToMemory(&pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: privPKCS8,
})
pubPKCS8, err := x509.MarshalPKIXPublicKey(&privKey.PublicKey)
if err != nil {
return "", "", err
}
pubPem := pem.EncodeToMemory(&pem.Block{
Type: "PUBLIC KEY",
Bytes: pubPKCS8,
})
return base64.StdEncoding.EncodeToString(pubPem), base64.StdEncoding.EncodeToString(privPem), nil
}
func main() {
srv := micro.NewService()
auth2ClientReg := auth2.ClientAuthRegistry()
auth2ClientReg.ForcePlugin("jwt")
flags := []cli.Flag{
// Generate
&cli.BoolFlag{
Name: "auth2_generate_keys",
Usage: "Generate keys for the config and/or the environment",
Value: false,
},
&cli.StringFlag{
Name: "auth2_generate_format",
Usage: "Format for \"auth2_generate_keys\", \"RSA4096\", \"RSA2048\" or \"Ed25519\"",
Value: "Ed25519",
},
// General
&cli.StringFlag{
Name: "auth2_sqld_router_basepath",
Usage: "Router basepath",
EnvVars: []string{"MICRO_AUTH2_SQLD_ROUTER_BASEPATH"},
Value: "auth",
},
// Keys
// given by they ClientAuth
&cli.StringFlag{
Name: "auth2_jwt_pub_key",
Usage: "Public access key PEM base64 encoded",
EnvVars: []string{"MICRO_AUTH2_JWT_PUB_KEY"},
},
&cli.StringFlag{
Name: "auth2_jwt_priv_key",
Usage: "Private access key PEM base64 encoded",
EnvVars: []string{"MICRO_AUTH2_JWT_PRIV_KEY"},
},
&cli.StringFlag{
Name: "auth2_jwt_refresh_pub_key",
Usage: "Public refresh key PEM base64 encoded",
EnvVars: []string{"MICRO_AUTH2_JWT_REFRESH_PUB_KEY"},
},
&cli.StringFlag{
Name: "auth2_jwt_refresh_priv_key",
Usage: "Private refresh key PEM base64 encoded",
EnvVars: []string{"MICRO_AUTH2_JWT_REFRESH_PRIV_KEY"},
},
// Token
&cli.Int64Flag{
Name: "auth2_jwt_refresh_expiry",
Usage: "Expire the refreshtoken after x seconds, default is one day",
EnvVars: []string{"MICRO_AUTH2_JWT_REFRESH_EXPIRY"},
Value: 86400,
},
&cli.Int64Flag{
Name: "auth2_jwt_access_expiry",
Usage: "Expire the accesstoken after x seconds, default is 15 minutes",
EnvVars: []string{"MICRO_AUTH2_JWT_ACCESS_EXPIRY"},
Value: 900,
},
&cli.StringSliceFlag{
Name: "auth2_jwt_audience",
Usage: "Add and expect this JWT audience",
EnvVars: []string{"MICRO_AUTH2_JWT_AUDIENCES"},
},
}
flags = ibun.AppendFlags(ilogger.AppendFlags(auth2ClientReg.AppendFlags(flags)))
authHandler := handler.NewHandler()
opts := []micro.Option{
micro.Name(config.Name),
micro.Version(config.Version),
micro.Flags(flags...),
micro.WrapHandler(auth2ClientReg.Plugin().Wrapper()),
micro.Action(func(c *cli.Context) error {
// Start the logger
if err := ilogger.Start(c); err != nil {
logger.Fatal(err)
return err
}
if c.Bool("auth2_generate_keys") {
var (
aPubKey string
aPrivKey string
rPubKey string
rPrivKey string
err error
)
// Just generate keys and print them to the commandline
switch c.String("auth2_generate_format") {
case "Ed25519":
aPubKey, aPrivKey, err = generateEd25519PEMKeyPair()
if err != nil {
ilogger.Logrus().Fatal(err)
}
rPubKey, rPrivKey, err = generateEd25519PEMKeyPair()
if err != nil {
ilogger.Logrus().Fatal(err)
}
case "RSA4096":
aPubKey, aPrivKey, err = generateRSAPEMKeyPair(4096)
if err != nil {
ilogger.Logrus().Fatal(err)
}
rPubKey, rPrivKey, err = generateRSAPEMKeyPair(4096)
if err != nil {
ilogger.Logrus().Fatal(err)
}
case "RSA2048":
aPubKey, aPrivKey, err = generateRSAPEMKeyPair(2048)
if err != nil {
ilogger.Logrus().Fatal(err)
}
rPubKey, rPrivKey, err = generateRSAPEMKeyPair(2048)
if err != nil {
ilogger.Logrus().Fatal(err)
}
default:
ilogger.Logrus().Fatalf("unknown key format: %s", c.String("auth2_generate_format"))
}
absPath, err := exec.LookPath(os.Args[0])
if err != nil {
// Don't fail here
absPath = os.Args[0]
}
fmt.Printf("# go.micro.auth %s JWT keys in PEM - generated using '%s %s'\n", c.String("auth2_generate_format"), absPath, strings.Join(os.Args[1:len(os.Args)], " "))
fmt.Printf("MICRO_AUTH2_JWT_PRIV_KEY=\"%s\"\n", aPrivKey)
fmt.Printf("MICRO_AUTH2_JWT_PUB_KEY=\"%s\"\n", aPubKey)
fmt.Printf("MICRO_AUTH2_JWT_REFRESH_PRIV_KEY=\"%s\"\n", rPrivKey)
fmt.Printf("MICRO_AUTH2_JWT_REFRESH_PUB_KEY=\"%s\"\n", rPubKey)
os.Exit(0)
}
if err := auth2ClientReg.Init(c, srv); err != nil {
ilogger.Logrus().Fatal(err)
}
authVerifier := endpointroles.NewVerifier()
authVerifier.AddRules(
endpointroles.RouterRule,
endpointroles.NewRule(
endpointroles.Endpoint(authpb.AuthService.Delete),
endpointroles.RolesAllow(auth2.RolesServiceAndAdmin),
),
endpointroles.NewRule(
endpointroles.Endpoint(authpb.AuthService.Detail),
endpointroles.RolesAllow(auth2.RolesServiceAndUsersAndAdmin),
),
endpointroles.NewRule(
endpointroles.Endpoint(authpb.AuthService.Inspect),
endpointroles.RolesAllow(auth2.RolesServiceAndUsersAndAdmin),
),
endpointroles.NewRule(
endpointroles.Endpoint(authpb.AuthService.List),
endpointroles.RolesAllow(auth2.RolesServiceAndAdmin),
),
endpointroles.NewRule(
endpointroles.Endpoint(authpb.AuthService.Login),
endpointroles.RolesAllow(auth2.RolesAllAndAnon),
),
endpointroles.NewRule(
endpointroles.Endpoint(authpb.AuthService.Refresh),
endpointroles.RolesAllow(auth2.RolesUsersAndAdmin),
),
endpointroles.NewRule(
endpointroles.Endpoint(authpb.AuthService.Register),
endpointroles.RolesAllow(auth2.RolesAllAndAnon),
),
endpointroles.NewRule(
endpointroles.Endpoint(authpb.AuthService.UpdateRoles),
endpointroles.RolesAllow(auth2.RolesAdmin),
),
)
auth2ClientReg.Plugin().SetVerifier(authVerifier)
// Connect to the database
if err := ibun.Start(c); err != nil {
ilogger.Logrus().Fatal(err)
}
// Check if we got keys
if c.String("auth2_jwt_pub_key") == "" || c.String("auth2_jwt_priv_key") == "" || c.String("auth2_jwt_refresh_pub_key") == "" || c.String("auth2_jwt_refresh_priv_key") == "" {
ilogger.Logrus().Fatal(ErrorNoKeys)
}
// Check the other handler cli arguments
if c.Int64("auth2_jwt_access_expiry") < 1 {
ilogger.Logrus().Fatal(errors.New("MICRO_AUTH2_JWT_ACCESS_EXPIRY must be great than 0"))
}
if c.Int64("auth2_jwt_refresh_expiry") < 1 {
ilogger.Logrus().Fatal(errors.New("MICRO_AUTH2_JWT_REFRESH_EXPIRY must be great than 0"))
}
if c.StringSlice("auth2_jwt_audience") == nil {
ilogger.Logrus().Fatal(errors.New("MICRO_AUTH2_JWT_AUDIENCES must be given"))
}
if err := authHandler.Init(handler.InitConfig{
Audiences: c.StringSlice("auth2_jwt_audience"),
RefreshTokenExpiry: c.Int64("auth2_jwt_refresh_expiry"),
AccessTokenExpiry: c.Int64("auth2_jwt_access_expiry"),
AccessTokenPubKey: c.String("auth2_jwt_pub_key"),
AccessTokenPrivKey: c.String("auth2_jwt_priv_key"),
RefreshTokenPubKey: c.String("auth2_jwt_refresh_pub_key"),
RefreshTokenPrivKey: c.String("auth2_jwt_refresh_priv_key"),
}); err != nil {
ilogger.Logrus().Fatal(err)
}
authpb.RegisterAuthServiceHandler(srv.Server(), authHandler)
// Register with https://jochum.dev/jo-micro/router
r := router.NewHandler(
c.String("auth2_sqld_router_basepath"),
router.NewRoute(
router.Method(router.MethodGet),
router.Path("/routes"),
router.Endpoint("routes"),
),
)
r.RegisterWithServer(srv.Server())
return nil
}),
}
srv.Init(opts...)
// Run server
if err := srv.Run(); err != nil {
ilogger.Logrus().Fatal(err)
}
// Disconnect from the database
if err := ibun.Stop(); err != nil {
ilogger.Logrus().Fatal(err)
}
// Stop the auth Plugin
if err := auth2ClientReg.Stop(); err != nil {
ilogger.Logrus().Fatal(err)
}
// Stop the logger
if err := ilogger.Stop(); err != nil {
logger.Fatal(err)
}
}

@ -0,0 +1,9 @@
BEGIN;
DROP TABLE IF EXISTS public.users;
DROP TABLE IF EXISTS public.roles;
DROP TABLE IF EXISTS public.users_roles;
DROP TABLE IF EXISTS public.tokens;
DROP TABLE IF EXISTS public.users_tokens;
COMMIT;

@ -0,0 +1,44 @@
BEGIN;
CREATE TABLE public.roles
(
id bigserial PRIMARY KEY,
name varchar(32) COLLATE pg_catalog."default" NOT NULL,
created_at TIMESTAMPTZ DEFAULT Now() NOT NULL,
updated_at TIMESTAMPTZ NULL,
deleted_at TIMESTAMPTZ NULL
);
CREATE UNIQUE INDEX name_idx ON public.roles (name) WHERE (deleted_at IS NULL);
CREATE TABLE public.users
(
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
username varchar(255) COLLATE pg_catalog."default" NOT NULL,
password varchar(255) COLLATE pg_catalog."default" NOT NULL,
email varchar(255) COLLATE pg_catalog."default" NOT NULL,
created_at TIMESTAMPTZ DEFAULT Now() NOT NULL,
updated_at TIMESTAMPTZ NULL,
deleted_at TIMESTAMPTZ NULL
);
CREATE UNIQUE INDEX username_idx ON public.users (username) WHERE (deleted_at IS NULL);
CREATE UNIQUE INDEX email_idx ON public.users (email) WHERE (deleted_at IS NULL);
CREATE TABLE public.users_roles
(
user_id UUID NOT NULL,
role_id BIGINT NOT NULL,
UNIQUE(role_id, user_id),
FOREIGN KEY(user_id) REFERENCES public.users(id) ON DELETE CASCADE,
FOREIGN KEY(role_id) REFERENCES public.roles(id) ON DELETE CASCADE
);
CREATE INDEX user_id_idx ON users_roles (user_id);
CREATE INDEX role_id_idx ON users_roles (role_id);
INSERT INTO roles (name) VALUES ('service'), ('user'), ('admin'), ('superadmin');
INSERT INTO users (id, username, password, email) VALUES ('2e4d8ed5-934d-4cd2-84fb-bd650d3a1ded', 'admin', '$argon2id$v=19$m=131072,t=4,p=4$sMaZvvQn2uWrISQICSbBqQ$L9tNlTTs4ldx0Ry+8Ctu8trSN27Q5iY68iWLjtprOfY', 'admin@wz2100.net');
INSERT INTO users_roles (user_id, role_id) VALUES ('2e4d8ed5-934d-4cd2-84fb-bd650d3a1ded', 2), ('2e4d8ed5-934d-4cd2-84fb-bd650d3a1ded', 3), ('2e4d8ed5-934d-4cd2-84fb-bd650d3a1ded', 4);
COMMIT;

@ -1,71 +0,0 @@
package config
var (
Version = "0.0.1-dev0"
)
const (
Name = "go.micro.auth"
PkgPath = "jochum.dev/jo-micro/auth2"
)
const (
EnvDev = "dev"
EnvProd = "prod"
)
type Config struct {
Auth AuthConfig
}
type ServerConfig struct {
Env string
RouterURI string
}
type TokenKeys struct {
PrivKey string
PubKey string
}
type AuthConfig struct {
Server ServerConfig
RefreshTokenExpiry int
AccessTokenExpiry int
AccessToken TokenKeys
RefreshToken TokenKeys
}
func GetConfig() *Config {
return &_cfg
}
func GetServerConfig() ServerConfig {
return _cfg.Auth.Server
}
func GetAuthConfig() AuthConfig {
return _cfg.Auth
}
// internal instance of Config with defaults
var _cfg = Config{
Auth: AuthConfig{
Server: ServerConfig{
Env: EnvProd,
RouterURI: "auth",
},
RefreshTokenExpiry: 86400 * 14, // 14 days
AccessTokenExpiry: 900, // 15 minutes
AccessToken: TokenKeys{
PrivKey: "",
PubKey: "",
},
RefreshToken: TokenKeys{
PrivKey: "",
PubKey: "",
},
},
}

@ -1,129 +0,0 @@
package main
import (
"crypto/ed25519"
"encoding/base64"
"errors"
"fmt"
"log"
"os"
"os/exec"
"strings"
"github.com/urfave/cli/v2"
"go-micro.dev/v4"
"go-micro.dev/v4/logger"
"jochum.dev/jo-micro/auth2/cmd/microauthsqld/config"
iconfig "jochum.dev/jo-micro/auth2/internal/config"
iLogger "jochum.dev/jo-micro/auth2/internal/logger"
"jochum.dev/jo-micro/router"
"jochum.dev/jo-micro/auth2/internal/bun"
)
var (
ErrorNoKeys = errors.New("config AUTH_ACCESS_TOKEN_*_KEY or AUTH_REFRESH_TOKEN_*_KEY not given")
)
func main() {
if err := iconfig.Load(config.GetConfig()); err != nil {
logger.Fatal(err)
}
srv := micro.NewService()
flags := []cli.Flag{
&cli.BoolFlag{
Name: "generate-keys",
Usage: "Generate keys for the config and/or the environment",
Value: false,
},
}
flags = append(flags, bun.Flags()...)
flags = append(flags, iLogger.Flags()...)
opts := []micro.Option{
micro.Name(config.Name),
micro.Version(config.Version),
micro.Flags(flags...),
micro.Action(func(c *cli.Context) error {
if c.Bool("generate-keys") {
// Just generate keys and print them to the commandline
aPubKeyB, aPrivKeyB, err := ed25519.GenerateKey(nil)
if err != nil {
log.Fatal(err)
return err
}
rPubKeyB, rPrivKeyB, err := ed25519.GenerateKey(nil)
if err != nil {
log.Fatal(err)
return err
}
absPath, err := exec.LookPath(os.Args[0])
if err != nil {
// Don't fail here
absPath = os.Args[0]
}
fmt.Printf("# go.micro.auth ed25519 JWT keys - generated using '%s %s'\n", absPath, strings.Join(os.Args[1:len(os.Args)], " "))
fmt.Printf("AUTH_ACCESSTOKEN_PRIVKEY=\"%s\"\n", base64.StdEncoding.EncodeToString(aPrivKeyB))
fmt.Printf("AUTH_ACCESSTOKEN_PUBKEY=\"%s\"\n", base64.StdEncoding.EncodeToString(aPubKeyB))
fmt.Printf("AUTH_REFRESHTOKEN_PRIVKEY=\"%s\"\n", base64.StdEncoding.EncodeToString(rPrivKeyB))
fmt.Printf("AUTH_REFRESHTOKEN_PUBKEY=\"%s\"\n", base64.StdEncoding.EncodeToString(rPubKeyB))
os.Exit(0)
}
// Start the logger
if err := iLogger.Start(c); err != nil {
log.Fatal(err)
return err
}
// Connect to the database
if err := bun.Start(c); err != nil {
log.Fatal(err)
return err
}
// Check if we got keys
authConfig := config.GetAuthConfig()
if authConfig.AccessToken.PrivKey == "" || authConfig.AccessToken.PubKey == "" || authConfig.RefreshToken.PrivKey == "" || authConfig.RefreshToken.PubKey == "" {
log.Fatal(ErrorNoKeys)
return ErrorNoKeys
}
// Register with https://jochum.dev/jo-micro/router
r := router.NewHandler(
config.GetServerConfig().RouterURI,
router.NewRoute(
router.Method(router.MethodGet),
router.Path("/routes"),
router.Endpoint("routes"),
),
)
r.RegisterWithServer(srv.Server())
return nil
}),
}
srv.Init(opts...)
// Run server
if err := srv.Run(); err != nil {
logger.Fatal(err)
}
// Disconnect from the database
if err := bun.Stop(); err != nil {
logger.Fatal(err)
}
// Stop the logger
if err := iLogger.Stop(); err != nil {
logger.Fatal(err)
}
}

@ -1,5 +1,8 @@
ARG DOCKER_IO=docker.io
ARG DOCKER_ORG_JO_MICRO=docker.io/jomicro
# STEP 1 build executable binary
FROM registry.fk.jochum.dev/jo-micro/builder:latest AS builder
FROM ${DOCKER_ORG_JO_MICRO}/builder:latest AS builder
# Create appuser (/etc/passwd entry for the runner container)
RUN useradd appuser
@ -7,23 +10,23 @@ RUN useradd appuser
ARG VERSION
COPY . /code/
WORKDIR /code
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -installsuffix cgo -ldflags="-w -s -X 'jochum.dev/jo-micro/auth2/cmd/microauthsqld/config.Version=$VERSION'" -o /usr/local/bin/microauthsqld jochum.dev/jo-micro/auth2/cmd/microauthsqld
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -installsuffix cgo -ldflags="-w -s -X 'jochum.dev/jo-micro/auth2/cmd/microauth2sqld/config.Version=$VERSION'" -o /usr/local/bin/microauth2sqld jochum.dev/jo-micro/auth2/cmd/microauth2sqld
# STEP 2 build a small image
# start from busybox
FROM busybox
FROM ${DOCKER_IO}/library/busybox:latest
LABEL maintainer="René Jochum <rene@jochum.dev>"
# Copy certs, passwd and binary from builder
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /etc/passwd /etc/passwd
COPY --from=builder /usr/local/bin/microauthsqld /usr/local/bin/microauthsqld
RUN chmod +x /usr/local/bin/microauthsqld
COPY --from=builder /usr/local/bin/microauth2sqld /usr/local/bin/microauth2sqld
RUN chmod +x /usr/local/bin/microauth2sqld
COPY ./cmd/microauthsqld/migrations /migrations
COPY ./cmd/microauth2sqld/migrations /migrations
# Run as appuser
USER appuser
CMD [ "/usr/local/bin/microauthsqld" ]
CMD [ "/usr/local/bin/microauth2sqld" ]

@ -0,0 +1,19 @@
#!/bin/sh
# From: https://stackoverflow.com/a/20909045
## Usage:
## . ./env.sh ; $COMMAND
## . ./env.sh ; echo ${MINIENTREGA_FECHALIMITE}
unamestr=$(uname)
if [ "$unamestr" = 'Linux' ]; then
export $(grep -v '^#' .env | xargs -d '\n')
elif [ "$unamestr" = 'FreeBSD' ] || [ "$unamestr" = 'Darwin' ]; then
export $(grep -v '^#' .env | xargs -0)
fi

@ -5,75 +5,61 @@ go 1.19
require (
github.com/avast/retry-go v3.0.0+incompatible
github.com/go-micro/plugins/v4/broker/nats v1.1.1-0.20220908125827-e0369dde429b
github.com/go-micro/plugins/v4/config/encoder/toml v1.1.0
github.com/go-micro/plugins/v4/config/encoder/yaml v1.1.0
github.com/go-micro/plugins/v4/logger/logrus v1.1.0
github.com/go-micro/plugins/v4/registry/nats v1.1.1-0.20220908125827-e0369dde429b
github.com/go-micro/plugins/v4/transport/grpc v1.1.0
github.com/go-micro/plugins/v4/transport/nats v1.1.1-0.20220908125827-e0369dde429b
github.com/golang-jwt/jwt/v4 v4.4.2
github.com/golang-migrate/migrate v3.5.4+incompatible
github.com/golang-migrate/migrate/v4 v4.15.2
github.com/google/uuid v1.3.0
github.com/jackc/pgx v3.6.2+incompatible
github.com/pkg/errors v0.9.1
github.com/sirupsen/logrus v1.9.0
github.com/uptrace/bun v1.1.8
github.com/uptrace/bun/dialect/pgdialect v1.1.8
github.com/uptrace/bun/extra/bundebug v1.1.8
github.com/urfave/cli/v2 v2.16.3
go-micro.dev/v4 v4.8.1
golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0
google.golang.org/protobuf v1.28.1
jochum.dev/jo-micro/router v0.2.3
jochum.dev/jo-micro/router v0.2.4
)
require (
github.com/BurntSushi/toml v1.2.0 // indirect
github.com/Microsoft/go-winio v0.5.2 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20220824120805-4b6e5c587895 // indirect
github.com/acomagu/bufpipe v1.0.3 // indirect
github.com/bitly/go-simplejson v0.5.0 // indirect
github.com/cloudflare/circl v1.2.0 // indirect
github.com/cockroachdb/apd v1.1.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/docker/distribution v2.8.1+incompatible // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/evanphx/json-patch/v5 v5.6.0 // indirect
github.com/fatih/color v1.13.0 // indirect
github.com/felixge/httpsnoop v1.0.3 // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/gin-gonic/gin v1.8.1 // indirect
github.com/go-acme/lego/v4 v4.8.0 // indirect
github.com/go-git/gcfg v1.5.0 // indirect
github.com/go-git/go-billy/v5 v5.3.1 // indirect
github.com/go-git/go-git/v5 v5.4.2 // indirect
github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.18.0 // indirect
github.com/go-playground/validator/v10 v10.11.1 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect
github.com/gobwas/ws v1.1.0 // indirect
github.com/goccy/go-json v0.9.11 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/go-cmp v0.5.8 // indirect
github.com/gorilla/handlers v1.5.1 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/imdario/mergo v0.3.13 // indirect
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/klauspost/compress v1.15.10 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/kr/pretty v0.3.0 // indirect
github.com/lib/pq v1.10.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect
github.com/miekg/dns v1.1.50 // indirect
github.com/minio/highwayhash v1.0.2 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/nats-io/jwt/v2 v2.3.0 // indirect
github.com/nats-io/nats.go v1.17.0 // indirect
github.com/nats-io/nkeys v0.3.0 // indirect
@ -81,26 +67,26 @@ require (
github.com/nxadm/tail v1.4.8 // indirect
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
github.com/pelletier/go-toml/v2 v2.0.5 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/rogpeppe/go-internal v1.8.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sergi/go-diff v1.2.0 // indirect
github.com/shopspring/decimal v1.3.1 // indirect
github.com/stretchr/testify v1.8.0 // indirect
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect
github.com/ugorji/go/codec v1.2.7 // indirect
github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
github.com/xanzy/ssh-agent v0.3.2 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 // indirect
go.uber.org/atomic v1.10.0 // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/net v0.0.0-20220909164309-bea034e7d591 // indirect
golang.org/x/net v0.0.0-20220920203100-d0c6ba3f52d9 // indirect
golang.org/x/sync v0.0.0-20220907140024-f12130a52804 // indirect
golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 // indirect
golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/tools v0.1.12 // indirect
google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa // indirect
google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006 // indirect
google.golang.org/grpc v1.49.0 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)

1756
go.sum

File diff suppressed because it is too large Load Diff

@ -0,0 +1,115 @@
// From: https://www.alexedwards.net/blog/how-to-hash-and-verify-passwords-with-argon2-in-go
package argon2
import (
"crypto/rand"
"crypto/subtle"
"encoding/base64"
"errors"
"fmt"
"strings"
"golang.org/x/crypto/argon2"
)
type Params struct {
memory uint32
iterations uint32
parallelism uint8
saltLength uint32
keyLength uint32
}
var DefaultParams = &Params{
memory: 128 * 1024,
iterations: 4,
parallelism: 4,
saltLength: 16,
keyLength: 32,
}
func Hash(password string, p *Params) (encodedHash string, err error) {
salt, err := generateRandomBytes(p.saltLength)
if err != nil {
return "", err
}
hash := argon2.IDKey([]byte(password), salt, p.iterations, p.memory, p.parallelism, p.keyLength)
// Base64 encode the salt and hashed password.
b64Salt := base64.RawStdEncoding.EncodeToString(salt)
b64Hash := base64.RawStdEncoding.EncodeToString(hash)
// Return a string using the standard encoded hash representation.
encodedHash = fmt.Sprintf("$argon2id$v=%d$m=%d,t=%d,p=%d$%s$%s", argon2.Version, p.memory, p.iterations, p.parallelism, b64Salt, b64Hash)
return encodedHash, nil
}
func Verify(password string, encodedHash string) (bool, error) {
// Extract the parameters, salt and derived key from the encoded password
// hash.
p, salt, hash, err := decodeHash(encodedHash)
if err != nil {
return false, err
}
// Derive the key from the other password using the same parameters.
otherHash := argon2.IDKey([]byte(password), salt, p.iterations, p.memory, p.parallelism, p.keyLength)
// Check that the contents of the hashed passwords are identical. Note
// that we are using the subtle.ConstantTimeCompare() function for this
// to help prevent timing attacks.
if subtle.ConstantTimeCompare(hash, otherHash) == 1 {
return true, nil
}
return false, nil
}
func decodeHash(encodedHash string) (p *Params, salt, hash []byte, err error) {
vals := strings.Split(encodedHash, "$")
if len(vals) != 6 {
return nil, nil, nil, errors.New("the encoded hash is not in the correct format")
}
var version int
_, err = fmt.Sscanf(vals[2], "v=%d", &version)
if err != nil {
return nil, nil, nil, err
}
if version != argon2.Version {
return nil, nil, nil, errors.New("incompatible version of argon2")
}
p = &Params{}
_, err = fmt.Sscanf(vals[3], "m=%d,t=%d,p=%d", &p.memory, &p.iterations, &p.parallelism)
if err != nil {
return nil, nil, nil, err
}
salt, err = base64.RawStdEncoding.Strict().DecodeString(vals[4])
if err != nil {
return nil, nil, nil, err
}
p.saltLength = uint32(len(salt))
hash, err = base64.RawStdEncoding.Strict().DecodeString(vals[5])
if err != nil {
return nil, nil, nil, err
}
p.keyLength = uint32(len(hash))
return p, salt, hash, nil
}
func generateRandomBytes(n uint32) ([]byte, error) {
b := make([]byte, n)
_, err := rand.Read(b)
if err != nil {
return nil, err
}
return b, nil
}

@ -1,118 +0,0 @@
package bun
import (
"database/sql"
"errors"
"fmt"
"strings"
"github.com/golang-migrate/migrate"
migratePostgres "github.com/golang-migrate/migrate/database/postgres"
"github.com/jackc/pgx"
"github.com/jackc/pgx/log/logrusadapter"
"github.com/jackc/pgx/stdlib"
"github.com/uptrace/bun"
"github.com/uptrace/bun/dialect/pgdialect"
"github.com/uptrace/bun/extra/bundebug"
iLogger "jochum.dev/jo-micro/auth2/internal/logger"
"github.com/urfave/cli/v2"
)
var initialized = false
var SQLDB *sql.DB
var Bun *bun.DB
func Flags() []cli.Flag {
return []cli.Flag{
&cli.StringFlag{
Name: "database-url",
Usage: "bun Database URL",
EnvVars: []string{"DATABASE_URL"},
},
&cli.BoolFlag{
Name: "database-debug",
Usage: "Set it to the debug the database queries",
EnvVars: []string{"DATABASE_DEBUG"},
DefaultText: "false",
Value: false,
},
&cli.StringFlag{
Name: "migrations-table",
Value: "schema_migrations",
Usage: "Table to store migrations info",
EnvVars: []string{"MIGRATIONS_TABLE"},
},
&cli.StringFlag{
Name: "migrations-dir",
Value: "/migrations",
Usage: "Folder which contains migrations",
EnvVars: []string{"MIGRATIONS_DIR"},
},
}
}
func Intialized() bool {
return initialized
}
func Start(cli *cli.Context) error {
if initialized {
return nil
}
if strings.HasPrefix(cli.String("database-uri"), "postgres://") {
config, err := pgx.ParseURI(cli.String("database-url"))
if err != nil {
return err
}
config.PreferSimpleProtocol = true
if iLogger.Intialized() {
config.Logger = logrusadapter.NewLogger(iLogger.Logrus())
}
SQLDB = stdlib.OpenDB(config)
driver, err := migratePostgres.WithInstance(SQLDB, &migratePostgres.Config{MigrationsTable: cli.String("migrations-table")})
if err != nil {
return err
}
m, err := migrate.NewWithDatabaseInstance(
fmt.Sprintf("file://%s/postgres", cli.String("migrations-dir")),
"postgres", driver)
if err != nil {
return err
}
if err := m.Up(); err != migrate.ErrNoChange && err != nil {
return err
}
Bun = bun.NewDB(SQLDB, pgdialect.New())
if Bun == nil {
return errors.New("failed to create bun")
}
if cli.Bool("database-debug") {
// Print all queries to stdout.
Bun.AddQueryHook(bundebug.NewQueryHook(bundebug.WithVerbose(true)))
}
}
initialized = true
return nil
}
func Stop() error {
if err := SQLDB.Close(); err != nil {
return err
}
if err := Bun.Close(); err != nil {
return err
}
return nil
}

@ -1,75 +0,0 @@
package config
import (
"os"
"strings"
"github.com/go-micro/plugins/v4/config/encoder/toml"
"github.com/go-micro/plugins/v4/config/encoder/yaml"
"github.com/pkg/errors"
"go-micro.dev/v4/config"
"go-micro.dev/v4/config/reader"
"go-micro.dev/v4/config/reader/json"
"go-micro.dev/v4/config/source/env"
"go-micro.dev/v4/config/source/file"
"go-micro.dev/v4/logger"
"jochum.dev/jo-micro/auth2/internal/util"
)
// Load will load configurations and update it when changed
func Load(cfg interface{}) error {
var configor config.Config
var err error
switch strings.ToLower(os.Getenv("CONFIG_TYPE")) {
case "toml":
filename := "config.toml"
if name := os.Getenv("CONFIG_FILE"); len(name) > 0 {
filename = name
}
configor, err = config.NewConfig(
config.WithSource(file.NewSource(file.WithPath(filename))),
config.WithReader(json.NewReader(reader.WithEncoder(toml.NewEncoder()))),
)
case "yaml":
filename := "config.yaml"
if name := os.Getenv("CONFIG_FILE"); len(name) > 0 {
filename = name
}
configor, err = config.NewConfig(
config.WithSource(file.NewSource(file.WithPath(filename))),
config.WithReader(json.NewReader(reader.WithEncoder(yaml.NewEncoder()))),
)
default:
configor, err = config.NewConfig(
config.WithSource(env.NewSource()),
)
}
if err != nil {
return errors.Wrap(err, "configor.New")
}
if err := configor.Load(); err != nil {
return errors.Wrap(err, "configor.Load")
}
if err := configor.Scan(cfg); err != nil {
return errors.Wrap(err, "configor.Scan")
}
w, err := configor.Watch()
if err != nil {
return errors.Wrap(err, "configor.Watch")
}
util.GoSafe(func() {
for {
v, err := w.Next()
if err != nil {
logger.Error(err)
return
}
if err := v.Scan(cfg); err != nil {
logger.Error(err)
return
}
}
})
return nil
}

@ -0,0 +1,125 @@
package ibun
import (
"database/sql"
"fmt"
"strings"
"github.com/golang-migrate/migrate/v4"
migratePostgres "github.com/golang-migrate/migrate/v4/database/postgres"
_ "github.com/golang-migrate/migrate/v4/source/file"
"github.com/jackc/pgx"
"github.com/jackc/pgx/log/logrusadapter"
"github.com/jackc/pgx/stdlib"
"github.com/uptrace/bun"
"github.com/uptrace/bun/dialect/pgdialect"
"github.com/uptrace/bun/extra/bundebug"
"go-micro.dev/v4/errors"
"jochum.dev/jo-micro/auth2/internal/ilogger"
"jochum.dev/jo-micro/auth2/shared/sutil"
"github.com/urfave/cli/v2"
)
var initialized = false
var SQLDB *sql.DB
var Bun *bun.DB
func AppendFlags(flags []cli.Flag) []cli.Flag {
flags = sutil.AppendFlag(flags, &cli.StringFlag{
Name: "auth2_database_url",
Usage: "bun Database URL",
EnvVars: []string{"MICRO_AUTH2_DATABASE_URL"},
})
flags = sutil.AppendFlag(flags, &cli.BoolFlag{
Name: "auth2_database_debug",
Usage: "Set it to the debug the database queries",
EnvVars: []string{"MICRO_AUTH2_DATABASE_DEBUG"},
DefaultText: "false",
Value: false,
})
flags = sutil.AppendFlag(flags, &cli.StringFlag{
Name: "auth2_migrations_table",
Value: "schema_migrations",
Usage: "Table to store migrations info",
EnvVars: []string{"MICRO_AUTH2_MIGRATIONS_TABLE"},
})
flags = sutil.AppendFlag(flags, &cli.StringFlag{
Name: "auth2_migrations_dir",
Value: "/migrations",
Usage: "Folder which contains migrations",
EnvVars: []string{"MICRO_AUTH2_MIGRATIONS_DIR"},
})
return flags
}
func Intialized() bool {
return initialized
}
func Start(cli *cli.Context) error {
if initialized {
return nil
}
if cli.String("auth2_database_url") == "" {
return errors.InternalServerError("internal/ibun.Start|sqltype.empty", "MICRO_AUTH2_DATABASE_URL is required")
} else if strings.HasPrefix(cli.String("auth2_database_url"), "postgres://") {
config, err := pgx.ParseURI(cli.String("auth2_database_url"))
if err != nil {
return err
}
config.PreferSimpleProtocol = true
if ilogger.Intialized() {
config.Logger = logrusadapter.NewLogger(ilogger.Logrus())
}
SQLDB = stdlib.OpenDB(config)
driver, err := migratePostgres.WithInstance(SQLDB, &migratePostgres.Config{MigrationsTable: cli.String("auth2_migrations_table")})
if err != nil {
return err
}
m, err := migrate.NewWithDatabaseInstance(
fmt.Sprintf("file://%s/postgres", cli.String("auth2_migrations_dir")),
"postgres", driver)
if err != nil {
return errors.InternalServerError("internal/ibun.Start|migrate.NewWithDatabaseInstance", fmt.Sprintf("%s", err))
}
if err := m.Up(); err != migrate.ErrNoChange && err != nil {
return errors.InternalServerError("internal/ibun.Start|migrate.Up", fmt.Sprintf("%s", err))
}
Bun = bun.NewDB(SQLDB, pgdialect.New())
if Bun == nil {
return errors.InternalServerError("internal/ibun.Start|bun.NewDB", "failed to create bun")
}
if cli.Bool("auth2_database_debug") {
// Print all queries to stdout.
Bun.AddQueryHook(bundebug.NewQueryHook(bundebug.WithVerbose(true)))
}
} else {
return errors.InternalServerError("internal/ibun.Start|sqltype", "unknown MICRO_AUTH2_DATABASE_URL type")
}
initialized = true
return nil
}
func Stop() error {
if err := SQLDB.Close(); err != nil {
return err
}
if err := Bun.Close(); err != nil {
return err
}
return nil
}

@ -1,4 +1,4 @@
package logger
package ilogger
import (
"fmt"
@ -7,6 +7,7 @@ import (
microLogrus "github.com/go-micro/plugins/v4/logger/logrus"
microLogger "go-micro.dev/v4/logger"
"jochum.dev/jo-micro/auth2/shared/sutil"
"github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
@ -15,15 +16,13 @@ import (
var myLogger *logrus.Logger = nil
var initialized = false
func Flags() []cli.Flag {
return []cli.Flag{
&cli.StringFlag{
Name: "loglevel",
Value: "info",
Usage: "Logrus log level default 'info', {panic,fatal,error,warn,info,debug,trace} available",
EnvVars: []string{"LOG_LEVEL"},
},
}
func AppendFlags(flags []cli.Flag) []cli.Flag {
return sutil.AppendFlag(flags, &cli.StringFlag{
Name: "auth2_loglevel",
Value: "info",
Usage: "Logrus log level default 'info', {panic,fatal,error,warn,info,debug,trace} available",
EnvVars: []string{"MICRO_AUTH2_LOG_LEVEL"},
})
}
func Intialized() bool {
@ -43,7 +42,7 @@ func Start(cli *cli.Context) error {
return nil
}
lvl, err := logrus.ParseLevel(cli.String("loglevel"))
lvl, err := logrus.ParseLevel(cli.String("auth2_loglevel"))
if err != nil {
return err
}

@ -84,53 +84,6 @@ func (x *KeysReply) GetRefreshPubKey() []byte {
return nil
}
type TokenRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
AccessToken string `protobuf:"bytes,1,opt,name=accessToken,proto3" json:"accessToken,omitempty"`
}
func (x *TokenRequest) Reset() {
*x = TokenRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_authpb_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *TokenRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TokenRequest) ProtoMessage() {}
func (x *TokenRequest) ProtoReflect() protoreflect.Message {
mi := &file_authpb_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TokenRequest.ProtoReflect.Descriptor instead.
func (*TokenRequest) Descriptor() ([]byte, []int) {
return file_authpb_proto_rawDescGZIP(), []int{1}
}
func (x *TokenRequest) GetAccessToken() string {
if x != nil {
return x.AccessToken
}
return ""
}
type ListRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@ -143,7 +96,7 @@ type ListRequest struct {
func (x *ListRequest) Reset() {
*x = ListRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_authpb_proto_msgTypes[2]
mi := &file_authpb_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@ -156,7 +109,7 @@ func (x *ListRequest) String() string {
func (*ListRequest) ProtoMessage() {}
func (x *ListRequest) ProtoReflect() protoreflect.Message {
mi := &file_authpb_proto_msgTypes[2]
mi := &file_authpb_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@ -169,7 +122,7 @@ func (x *ListRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use ListRequest.ProtoReflect.Descriptor instead.
func (*ListRequest) Descriptor() ([]byte, []int) {
return file_authpb_proto_rawDescGZIP(), []int{2}
return file_authpb_proto_rawDescGZIP(), []int{1}
}
func (x *ListRequest) GetLimit() uint64 {
@ -191,17 +144,16 @@ type User struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
Issuer string `protobuf:"bytes,3,opt,name=issuer,proto3" json:"issuer,omitempty"`
Metadata map[string]string `protobuf:"bytes,4,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
Scopes []string `protobuf:"bytes,5,rep,name=scopes,proto3" json:"scopes,omitempty"`
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Username string `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"`
Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"`
Roles []string `protobuf:"bytes,4,rep,name=roles,proto3" json:"roles,omitempty"`
}
func (x *User) Reset() {
*x = User{}
if protoimpl.UnsafeEnabled {
mi := &file_authpb_proto_msgTypes[3]
mi := &file_authpb_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@ -214,7 +166,7 @@ func (x *User) String() string {
func (*User) ProtoMessage() {}
func (x *User) ProtoReflect() protoreflect.Message {
mi := &file_authpb_proto_msgTypes[3]
mi := &file_authpb_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@ -227,7 +179,7 @@ func (x *User) ProtoReflect() protoreflect.Message {
// Deprecated: Use User.ProtoReflect.Descriptor instead.
func (*User) Descriptor() ([]byte, []int) {
return file_authpb_proto_rawDescGZIP(), []int{3}
return file_authpb_proto_rawDescGZIP(), []int{2}
}
func (x *User) GetId() string {
@ -237,30 +189,23 @@ func (x *User) GetId() string {
return ""
}
func (x *User) GetType() string {
func (x *User) GetUsername() string {
if x != nil {
return x.Type
return x.Username
}
return ""
}
func (x *User) GetIssuer() string {
func (x *User) GetEmail() string {
if x != nil {
return x.Issuer
return x.Email
}
return ""
}
func (x *User) GetMetadata() map[string]string {
func (x *User) GetRoles() []string {
if x != nil {
return x.Metadata
}
return nil
}
func (x *User) GetScopes() []string {
if x != nil {
return x.Scopes
return x.Roles
}
return nil
}
@ -279,7 +224,7 @@ type UserListReply struct {
func (x *UserListReply) Reset() {
*x = UserListReply{}
if protoimpl.UnsafeEnabled {
mi := &file_authpb_proto_msgTypes[4]
mi := &file_authpb_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@ -292,7 +237,7 @@ func (x *UserListReply) String() string {
func (*UserListReply) ProtoMessage() {}
func (x *UserListReply) ProtoReflect() protoreflect.Message {
mi := &file_authpb_proto_msgTypes[4]
mi := &file_authpb_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@ -305,7 +250,7 @@ func (x *UserListReply) ProtoReflect() protoreflect.Message {
// Deprecated: Use UserListReply.ProtoReflect.Descriptor instead.
func (*UserListReply) Descriptor() ([]byte, []int) {
return file_authpb_proto_rawDescGZIP(), []int{4}
return file_authpb_proto_rawDescGZIP(), []int{3}
}
func (x *UserListReply) GetData() []*User {
@ -341,13 +286,14 @@ type UserIDRequest struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Optional if specified user must be admin
UserId string `protobuf:"bytes,1,opt,name=userId,proto3" json:"userId,omitempty"`
}
func (x *UserIDRequest) Reset() {
*x = UserIDRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_authpb_proto_msgTypes[5]
mi := &file_authpb_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@ -360,7 +306,7 @@ func (x *UserIDRequest) String() string {
func (*UserIDRequest) ProtoMessage() {}
func (x *UserIDRequest) ProtoReflect() protoreflect.Message {
mi := &file_authpb_proto_msgTypes[5]
mi := &file_authpb_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@ -373,7 +319,7 @@ func (x *UserIDRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use UserIDRequest.ProtoReflect.Descriptor instead.
func (*UserIDRequest) Descriptor() ([]byte, []int) {
return file_authpb_proto_rawDescGZIP(), []int{5}
return file_authpb_proto_rawDescGZIP(), []int{4}
}
func (x *UserIDRequest) GetUserId() string {
@ -395,7 +341,7 @@ type UpdateRolesRequest struct {
func (x *UpdateRolesRequest) Reset() {
*x = UpdateRolesRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_authpb_proto_msgTypes[6]
mi := &file_authpb_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@ -408,7 +354,7 @@ func (x *UpdateRolesRequest) String() string {
func (*UpdateRolesRequest) ProtoMessage() {}
func (x *UpdateRolesRequest) ProtoReflect() protoreflect.Message {
mi := &file_authpb_proto_msgTypes[6]
mi := &file_authpb_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@ -421,7 +367,7 @@ func (x *UpdateRolesRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use UpdateRolesRequest.ProtoReflect.Descriptor instead.
func (*UpdateRolesRequest) Descriptor() ([]byte, []int) {
return file_authpb_proto_rawDescGZIP(), []int{6}
return file_authpb_proto_rawDescGZIP(), []int{5}
}
func (x *UpdateRolesRequest) GetUserId() string {
@ -438,7 +384,7 @@ func (x *UpdateRolesRequest) GetRoles() []string {
return nil
}
type TokenReply struct {
type Token struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
@ -449,23 +395,23 @@ type TokenReply struct {
RefreshTokenExpiresAt int64 `protobuf:"varint,4,opt,name=refreshTokenExpiresAt,proto3" json:"refreshTokenExpiresAt,omitempty"`
}
func (x *TokenReply) Reset() {
*x = TokenReply{}
func (x *Token) Reset() {
*x = Token{}
if protoimpl.UnsafeEnabled {
mi := &file_authpb_proto_msgTypes[7]
mi := &file_authpb_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *TokenReply) String() string {
func (x *Token) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TokenReply) ProtoMessage() {}
func (*Token) ProtoMessage() {}
func (x *TokenReply) ProtoReflect() protoreflect.Message {
mi := &file_authpb_proto_msgTypes[7]
func (x *Token) ProtoReflect() protoreflect.Message {
mi := &file_authpb_proto_msgTypes[6]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@ -476,33 +422,33 @@ func (x *TokenReply) ProtoReflect() protoreflect.Message {
return mi.MessageOf(x)
}
// Deprecated: Use TokenReply.ProtoReflect.Descriptor instead.
func (*TokenReply) Descriptor() ([]byte, []int) {
return file_authpb_proto_rawDescGZIP(), []int{7}
// Deprecated: Use Token.ProtoReflect.Descriptor instead.
func (*Token) Descriptor() ([]byte, []int) {
return file_authpb_proto_rawDescGZIP(), []int{6}
}
func (x *TokenReply) GetAccessToken() string {
func (x *Token) GetAccessToken() string {
if x != nil {
return x.AccessToken
}
return ""
}
func (x *TokenReply) GetAccessTokenExpiresAt() int64 {
func (x *Token) GetAccessTokenExpiresAt() int64 {
if x != nil {
return x.AccessTokenExpiresAt
}
return 0
}
func (x *TokenReply) GetRefreshToken() string {
func (x *Token) GetRefreshToken() string {
if x != nil {
return x.RefreshToken
}
return ""
}
func (x *TokenReply) GetRefreshTokenExpiresAt() int64 {
func (x *Token) GetRefreshTokenExpiresAt() int64 {
if x != nil {
return x.RefreshTokenExpiresAt
}
@ -522,7 +468,7 @@ type RegisterRequest struct {
func (x *RegisterRequest) Reset() {
*x = RegisterRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_authpb_proto_msgTypes[8]
mi := &file_authpb_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@ -535,7 +481,7 @@ func (x *RegisterRequest) String() string {
func (*RegisterRequest) ProtoMessage() {}
func (x *RegisterRequest) ProtoReflect() protoreflect.Message {
mi := &file_authpb_proto_msgTypes[8]
mi := &file_authpb_proto_msgTypes[7]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@ -548,7 +494,7 @@ func (x *RegisterRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use RegisterRequest.ProtoReflect.Descriptor instead.
func (*RegisterRequest) Descriptor() ([]byte, []int) {
return file_authpb_proto_rawDescGZIP(), []int{8}
return file_authpb_proto_rawDescGZIP(), []int{7}
}
func (x *RegisterRequest) GetUsername() string {
@ -584,7 +530,7 @@ type LoginRequest struct {
func (x *LoginRequest) Reset() {
*x = LoginRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_authpb_proto_msgTypes[9]
mi := &file_authpb_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@ -597,7 +543,7 @@ func (x *LoginRequest) String() string {
func (*LoginRequest) ProtoMessage() {}
func (x *LoginRequest) ProtoReflect() protoreflect.Message {
mi := &file_authpb_proto_msgTypes[9]
mi := &file_authpb_proto_msgTypes[8]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@ -610,7 +556,7 @@ func (x *LoginRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use LoginRequest.ProtoReflect.Descriptor instead.
func (*LoginRequest) Descriptor() ([]byte, []int) {
return file_authpb_proto_rawDescGZIP(), []int{9}
return file_authpb_proto_rawDescGZIP(), []int{8}
}
func (x *LoginRequest) GetUsername() string {
@ -638,7 +584,7 @@ type RefreshTokenRequest struct {
func (x *RefreshTokenRequest) Reset() {
*x = RefreshTokenRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_authpb_proto_msgTypes[10]
mi := &file_authpb_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@ -651,7 +597,7 @@ func (x *RefreshTokenRequest) String() string {
func (*RefreshTokenRequest) ProtoMessage() {}
func (x *RefreshTokenRequest) ProtoReflect() protoreflect.Message {
mi := &file_authpb_proto_msgTypes[10]
mi := &file_authpb_proto_msgTypes[9]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@ -664,7 +610,7 @@ func (x *RefreshTokenRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use RefreshTokenRequest.ProtoReflect.Descriptor instead.
func (*RefreshTokenRequest) Descriptor() ([]byte, []int) {
return file_authpb_proto_rawDescGZIP(), []int{10}
return file_authpb_proto_rawDescGZIP(), []int{9}
}
func (x *RefreshTokenRequest) GetRefreshToken() string {
@ -674,6 +620,93 @@ func (x *RefreshTokenRequest) GetRefreshToken() string {
return ""
}
type JWTClaims struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
Issuer string `protobuf:"bytes,3,opt,name=issuer,proto3" json:"issuer,omitempty"`
Metadata map[string]string `protobuf:"bytes,4,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
Scopes []string `protobuf:"bytes,5,rep,name=scopes,proto3" json:"scopes,omitempty"`
Roles []string `protobuf:"bytes,6,rep,name=roles,proto3" json:"roles,omitempty"`
}
func (x *JWTClaims) Reset() {
*x = JWTClaims{}
if protoimpl.UnsafeEnabled {
mi := &file_authpb_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *JWTClaims) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*JWTClaims) ProtoMessage() {}
func (x *JWTClaims) ProtoReflect() protoreflect.Message {
mi := &file_authpb_proto_msgTypes[10]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use JWTClaims.ProtoReflect.Descriptor instead.
func (*JWTClaims) Descriptor() ([]byte, []int) {
return file_authpb_proto_rawDescGZIP(), []int{10}
}
func (x *JWTClaims) GetId() string {
if x != nil {
return x.Id
}
return ""
}
func (x *JWTClaims) GetType() string {
if x != nil {
return x.Type
}
return ""
}
func (x *JWTClaims) GetIssuer() string {
if x != nil {
return x.Issuer
}
return ""
}
func (x *JWTClaims) GetMetadata() map[string]string {
if x != nil {
return x.Metadata
}
return nil
}
func (x *JWTClaims) GetScopes() []string {
if x != nil {
return x.Scopes
}
return nil
}
func (x *JWTClaims) GetRoles() []string {
if x != nil {
return x.Roles
}
return nil
}
var File_authpb_proto protoreflect.FileDescriptor
var file_authpb_proto_rawDesc = []byte{
@ -686,100 +719,105 @@ var file_authpb_proto_rawDesc = []byte{
0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73,
0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x0a, 0x0d, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73,
0x68, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x72,
0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, 0x30, 0x0a, 0x0c,
0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b,
0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x3b,
0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a,
0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6c, 0x69,
0x6d, 0x69, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20,
0x01, 0x28, 0x04, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x22, 0xcf, 0x01, 0x0a, 0x04,
0x55, 0x73, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01,
0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x73, 0x73, 0x75,
0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72,
0x12, 0x36, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x03,
0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72,
0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08,
0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x63, 0x6f, 0x70,
0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73,
0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, 0x3b, 0x0a, 0x0b,
0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6c,
0x69, 0x6d, 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69,
0x74, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28,
0x04, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x22, 0x5e, 0x0a, 0x04, 0x55, 0x73, 0x65,
0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69,
0x64, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20,
0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a,
0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d,
0x61, 0x69, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03,
0x28, 0x09, 0x52, 0x05, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x22, 0x75, 0x0a, 0x0d, 0x55, 0x73, 0x65,
0x72, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x20, 0x0a, 0x04, 0x64, 0x61,
0x74, 0x61, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x70,
0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05,
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x63, 0x6f, 0x75,
0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28,
0x04, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73,
0x65, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74,
0x22, 0x27, 0x0a, 0x0d, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, 0x42, 0x0a, 0x12, 0x55, 0x70, 0x64,
0x61, 0x74, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x6f, 0x6c, 0x65, 0x73,
0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x22, 0xb7, 0x01,
0x0a, 0x05, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73,
0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x63,
0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x32, 0x0a, 0x14, 0x61, 0x63, 0x63,
0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41,
0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x14, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54,
0x6f, 0x6b, 0x65, 0x6e, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x12, 0x22, 0x0a,
0x0c, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20,
0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65,
0x6e, 0x12, 0x34, 0x0a, 0x15, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65,
0x6e, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03,
0x52, 0x15, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x45, 0x78,
0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x22, 0x5f, 0x0a, 0x0f, 0x52, 0x65, 0x67, 0x69, 0x73,
0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73,
0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73,
0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f,
0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f,
0x72, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28,
0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x46, 0x0a, 0x0c, 0x4c, 0x6f, 0x67, 0x69,
0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72,
0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72,
0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64,
0x22, 0x39, 0x0a, 0x13, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x72, 0x65, 0x66, 0x72, 0x65,
0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72,
0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xef, 0x01, 0x0a, 0x09,
0x4a, 0x57, 0x54, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70,
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a,
0x06, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x69,
0x73, 0x73, 0x75, 0x65, 0x72, 0x12, 0x3b, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
0x61, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62,
0x2e, 0x4a, 0x57, 0x54, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64,
0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61,
0x74, 0x61, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03,
0x28, 0x09, 0x52, 0x06, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x6f,
0x6c, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x72, 0x6f, 0x6c, 0x65, 0x73,
0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72,
0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x75, 0x0a,
0x0d, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x20,
0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x61,
0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61,
0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52,
0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18,
0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x16, 0x0a, 0x06,
0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6f, 0x66,
0x66, 0x73, 0x65, 0x74, 0x22, 0x27, 0x0a, 0x0d, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, 0x42, 0x0a,
0x12, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x72,
0x6f, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x72, 0x6f, 0x6c, 0x65,
0x73, 0x22, 0xbc, 0x01, 0x0a, 0x0a, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79,
0x12, 0x20, 0x0a, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b,
0x65, 0x6e, 0x12, 0x32, 0x0a, 0x14, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65,
0x6e, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03,
0x52, 0x14, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x45, 0x78, 0x70,
0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73,
0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65,
0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x34, 0x0a, 0x15, 0x72, 0x65,
0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65,
0x73, 0x41, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x15, 0x72, 0x65, 0x66, 0x72, 0x65,
0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74,
0x22, 0x5f, 0x0a, 0x0f, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12,
0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28,
0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65,
0x6d, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69,
0x6c, 0x22, 0x46, 0x0a, 0x0c, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a,
0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x39, 0x0a, 0x13, 0x52, 0x65, 0x66,
0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x12, 0x22, 0x0a, 0x0c, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54,
0x6f, 0x6b, 0x65, 0x6e, 0x32, 0xc3, 0x03, 0x0a, 0x0b, 0x41, 0x75, 0x74, 0x68, 0x53, 0x65, 0x72,
0x76, 0x69, 0x63, 0x65, 0x12, 0x34, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x13, 0x2e, 0x61,
0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x15, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4c,
0x69, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x2f, 0x0a, 0x06, 0x44, 0x65,
0x74, 0x61, 0x69, 0x6c, 0x12, 0x15, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, 0x55, 0x73,
0x65, 0x72, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x61, 0x75,
0x74, 0x68, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x22, 0x00, 0x12, 0x39, 0x0a, 0x06, 0x44,
0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x15, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, 0x55,
0x73, 0x65, 0x72, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67,
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45,
0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x39, 0x0a, 0x0b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65,
0x52, 0x6f, 0x6c, 0x65, 0x73, 0x12, 0x1a, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, 0x55,
0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x0c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x22,
0x00, 0x12, 0x33, 0x0a, 0x08, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x17, 0x2e,
0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e,
0x55, 0x73, 0x65, 0x72, 0x22, 0x00, 0x12, 0x33, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12,
0x14, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, 0x54,
0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x3c, 0x0a, 0x07, 0x52,
0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x12, 0x1b, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e,
0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, 0x54, 0x6f, 0x6b,
0x65, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x2f, 0x0a, 0x07, 0x49, 0x6e, 0x73,
0x70, 0x65, 0x63, 0x74, 0x12, 0x14, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, 0x54, 0x6f,
0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x61, 0x75, 0x74,
0x68, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x22, 0x00, 0x42, 0x38, 0x5a, 0x36, 0x6a, 0x6f,
0x63, 0x68, 0x75, 0x6d, 0x2e, 0x64, 0x65, 0x76, 0x2f, 0x6a, 0x6f, 0x2d, 0x6d, 0x69, 0x63, 0x72,
0x6f, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x32, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c,
0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x3b, 0x61, 0x75,
0x74, 0x68, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x32, 0xc0, 0x03,
0x0a, 0x0b, 0x41, 0x75, 0x74, 0x68, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x34, 0x0a,
0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x13, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, 0x4c,
0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x61, 0x75, 0x74,
0x68, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6c,
0x79, 0x22, 0x00, 0x12, 0x2f, 0x0a, 0x06, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x12, 0x15, 0x2e,
0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, 0x55, 0x73,
0x65, 0x72, 0x22, 0x00, 0x12, 0x39, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x15,
0x2e, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12,
0x39, 0x0a, 0x0b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x12, 0x1a,
0x2e, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x6f,
0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x61, 0x75, 0x74,
0x68, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x22, 0x00, 0x12, 0x33, 0x0a, 0x08, 0x52, 0x65,
0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x17, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e,
0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x0c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x22, 0x00, 0x12,
0x2e, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x14, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x70,
0x62, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0d,
0x2e, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x00, 0x12,
0x37, 0x0a, 0x07, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x12, 0x1b, 0x2e, 0x61, 0x75, 0x74,
0x68, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0d, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62,
0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x00, 0x12, 0x36, 0x0a, 0x07, 0x49, 0x6e, 0x73, 0x70,
0x65, 0x63, 0x74, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x11, 0x2e, 0x61, 0x75,
0x74, 0x68, 0x70, 0x62, 0x2e, 0x4a, 0x57, 0x54, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x73, 0x22, 0x00,
0x42, 0x38, 0x5a, 0x36, 0x6a, 0x6f, 0x63, 0x68, 0x75, 0x6d, 0x2e, 0x64, 0x65, 0x76, 0x2f, 0x6a,
0x6f, 0x2d, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x32, 0x2f, 0x69, 0x6e,
0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x61, 0x75, 0x74,
0x68, 0x70, 0x62, 0x3b, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
}
var (
@ -797,38 +835,38 @@ func file_authpb_proto_rawDescGZIP() []byte {
var file_authpb_proto_msgTypes = make([]protoimpl.MessageInfo, 12)
var file_authpb_proto_goTypes = []interface{}{
(*KeysReply)(nil), // 0: authpb.KeysReply
(*TokenRequest)(nil), // 1: authpb.TokenRequest
(*ListRequest)(nil), // 2: authpb.ListRequest
(*User)(nil), // 3: authpb.User
(*UserListReply)(nil), // 4: authpb.UserListReply
(*UserIDRequest)(nil), // 5: authpb.UserIDRequest
(*UpdateRolesRequest)(nil), // 6: authpb.UpdateRolesRequest
(*TokenReply)(nil), // 7: authpb.TokenReply
(*RegisterRequest)(nil), // 8: authpb.RegisterRequest
(*LoginRequest)(nil), // 9: authpb.LoginRequest
(*RefreshTokenRequest)(nil), // 10: authpb.RefreshTokenRequest
nil, // 11: authpb.User.MetadataEntry
(*ListRequest)(nil), // 1: authpb.ListRequest
(*User)(nil), // 2: authpb.User
(*UserListReply)(nil), // 3: authpb.UserListReply
(*UserIDRequest)(nil), // 4: authpb.UserIDRequest
(*UpdateRolesRequest)(nil), // 5: authpb.UpdateRolesRequest
(*Token)(nil), // 6: authpb.Token
(*RegisterRequest)(nil), // 7: authpb.RegisterRequest
(*LoginRequest)(nil), // 8: authpb.LoginRequest
(*RefreshTokenRequest)(nil), // 9: authpb.RefreshTokenRequest
(*JWTClaims)(nil), // 10: authpb.JWTClaims
nil, // 11: authpb.JWTClaims.MetadataEntry
(*emptypb.Empty)(nil), // 12: google.protobuf.Empty
}
var file_authpb_proto_depIdxs = []int32{
11, // 0: authpb.User.metadata:type_name -> authpb.User.MetadataEntry
3, // 1: authpb.UserListReply.data:type_name -> authpb.User
2, // 2: authpb.AuthService.List:input_type -> authpb.ListRequest
5, // 3: authpb.AuthService.Detail:input_type -> authpb.UserIDRequest
5, // 4: authpb.AuthService.Delete:input_type -> authpb.UserIDRequest
6, // 5: authpb.AuthService.UpdateRoles:input_type -> authpb.UpdateRolesRequest
8, // 6: authpb.AuthService.Register:input_type -> authpb.RegisterRequest
9, // 7: authpb.AuthService.Login:input_type -> authpb.LoginRequest
10, // 8: authpb.AuthService.Refresh:input_type -> authpb.RefreshTokenRequest
1, // 9: authpb.AuthService.Inspect:input_type -> authpb.TokenRequest
4, // 10: authpb.AuthService.List:output_type -> authpb.UserListReply
3, // 11: authpb.AuthService.Detail:output_type -> authpb.User
2, // 0: authpb.UserListReply.data:type_name -> authpb.User
11, // 1: authpb.JWTClaims.metadata:type_name -> authpb.JWTClaims.MetadataEntry
1, // 2: authpb.AuthService.List:input_type -> authpb.ListRequest
4, // 3: authpb.AuthService.Detail:input_type -> authpb.UserIDRequest
4, // 4: authpb.AuthService.Delete:input_type -> authpb.UserIDRequest
5, // 5: authpb.AuthService.UpdateRoles:input_type -> authpb.UpdateRolesRequest
7, // 6: authpb.AuthService.Register:input_type -> authpb.RegisterRequest
8, // 7: authpb.AuthService.Login:input_type -> authpb.LoginRequest
9, // 8: authpb.AuthService.Refresh:input_type -> authpb.RefreshTokenRequest
12, // 9: authpb.AuthService.Inspect:input_type -> google.protobuf.Empty
3, // 10: authpb.AuthService.List:output_type -> authpb.UserListReply
2, // 11: authpb.AuthService.Detail:output_type -> authpb.User
12, // 12: authpb.AuthService.Delete:output_type -> google.protobuf.Empty
3, // 13: authpb.AuthService.UpdateRoles:output_type -> authpb.User
3, // 14: authpb.AuthService.Register:output_type -> authpb.User
7, // 15: authpb.AuthService.Login:output_type -> authpb.TokenReply
7, // 16: authpb.AuthService.Refresh:output_type -> authpb.TokenReply
3, // 17: authpb.AuthService.Inspect:output_type -> authpb.User
2, // 13: authpb.AuthService.UpdateRoles:output_type -> authpb.User
2, // 14: authpb.AuthService.Register:output_type -> authpb.User
6, // 15: authpb.AuthService.Login:output_type -> authpb.Token
6, // 16: authpb.AuthService.Refresh:output_type -> authpb.Token
10, // 17: authpb.AuthService.Inspect:output_type -> authpb.JWTClaims
10, // [10:18] is the sub-list for method output_type
2, // [2:10] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
@ -855,7 +893,7 @@ func file_authpb_proto_init() {
}
}
file_authpb_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*TokenRequest); i {
switch v := v.(*ListRequest); i {
case 0:
return &v.state
case 1:
@ -867,7 +905,7 @@ func file_authpb_proto_init() {
}
}
file_authpb_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ListRequest); i {
switch v := v.(*User); i {
case 0:
return &v.state
case 1:
@ -879,7 +917,7 @@ func file_authpb_proto_init() {
}
}
file_authpb_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*User); i {
switch v := v.(*UserListReply); i {
case 0:
return &v.state
case 1:
@ -891,7 +929,7 @@ func file_authpb_proto_init() {
}
}
file_authpb_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*UserListReply); i {
switch v := v.(*UserIDRequest); i {
case 0:
return &v.state
case 1:
@ -903,7 +941,7 @@ func file_authpb_proto_init() {
}
}
file_authpb_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*UserIDRequest); i {
switch v := v.(*UpdateRolesRequest); i {
case 0:
return &v.state
case 1:
@ -915,7 +953,7 @@ func file_authpb_proto_init() {
}
}
file_authpb_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*UpdateRolesRequest); i {
switch v := v.(*Token); i {
case 0:
return &v.state
case 1:
@ -927,7 +965,7 @@ func file_authpb_proto_init() {
}
}
file_authpb_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*TokenReply); i {
switch v := v.(*RegisterRequest); i {
case 0:
return &v.state
case 1:
@ -939,7 +977,7 @@ func file_authpb_proto_init() {
}
}
file_authpb_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RegisterRequest); i {
switch v := v.(*LoginRequest); i {
case 0:
return &v.state
case 1:
@ -951,7 +989,7 @@ func file_authpb_proto_init() {
}
}
file_authpb_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*LoginRequest); i {
switch v := v.(*RefreshTokenRequest); i {
case 0:
return &v.state
case 1:
@ -963,7 +1001,7 @@ func file_authpb_proto_init() {
}
}
file_authpb_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RefreshTokenRequest); i {
switch v := v.(*JWTClaims); i {
case 0:
return &v.state
case 1:

@ -46,9 +46,9 @@ type AuthService interface {
Delete(ctx context.Context, in *UserIDRequest, opts ...client.CallOption) (*emptypb.Empty, error)
UpdateRoles(ctx context.Context, in *UpdateRolesRequest, opts ...client.CallOption) (*User, error)
Register(ctx context.Context, in *RegisterRequest, opts ...client.CallOption) (*User, error)
Login(ctx context.Context, in *LoginRequest, opts ...client.CallOption) (*TokenReply, error)
Refresh(ctx context.Context, in *RefreshTokenRequest, opts ...client.CallOption) (*TokenReply, error)
Inspect(ctx context.Context, in *TokenRequest, opts ...client.CallOption) (*User, error)
Login(ctx context.Context, in *LoginRequest, opts ...client.CallOption) (*Token, error)
Refresh(ctx context.Context, in *RefreshTokenRequest, opts ...client.CallOption) (*Token, error)
Inspect(ctx context.Context, in *emptypb.Empty, opts ...client.CallOption) (*JWTClaims, error)
}
type authService struct {
@ -113,9 +113,9 @@ func (c *authService) Register(ctx context.Context, in *RegisterRequest, opts ..
return out, nil
}
func (c *authService) Login(ctx context.Context, in *LoginRequest, opts ...client.CallOption) (*TokenReply, error) {
func (c *authService) Login(ctx context.Context, in *LoginRequest, opts ...client.CallOption) (*Token, error) {
req := c.c.NewRequest(c.name, "AuthService.Login", in)
out := new(TokenReply)
out := new(Token)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
@ -123,9 +123,9 @@ func (c *authService) Login(ctx context.Context, in *LoginRequest, opts ...clien
return out, nil
}
func (c *authService) Refresh(ctx context.Context, in *RefreshTokenRequest, opts ...client.CallOption) (*TokenReply, error) {
func (c *authService) Refresh(ctx context.Context, in *RefreshTokenRequest, opts ...client.CallOption) (*Token, error) {
req := c.c.NewRequest(c.name, "AuthService.Refresh", in)
out := new(TokenReply)
out := new(Token)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
@ -133,9 +133,9 @@ func (c *authService) Refresh(ctx context.Context, in *RefreshTokenRequest, opts
return out, nil
}
func (c *authService) Inspect(ctx context.Context, in *TokenRequest, opts ...client.CallOption) (*User, error) {
func (c *authService) Inspect(ctx context.Context, in *emptypb.Empty, opts ...client.CallOption) (*JWTClaims, error) {
req := c.c.NewRequest(c.name, "AuthService.Inspect", in)
out := new(User)
out := new(JWTClaims)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
@ -155,9 +155,9 @@ type AuthServiceHandler interface {
Delete(context.Context, *UserIDRequest, *emptypb.Empty) error
UpdateRoles(context.Context, *UpdateRolesRequest, *User) error
Register(context.Context, *RegisterRequest, *User) error
Login(context.Context, *LoginRequest, *TokenReply) error
Refresh(context.Context, *RefreshTokenRequest, *TokenReply) error
Inspect(context.Context, *TokenRequest, *User) error
Login(context.Context, *LoginRequest, *Token) error
Refresh(context.Context, *RefreshTokenRequest, *Token) error
Inspect(context.Context, *emptypb.Empty, *JWTClaims) error
}
func RegisterAuthServiceHandler(s server.Server, hdlr AuthServiceHandler, opts ...server.HandlerOption) error {
@ -167,9 +167,9 @@ func RegisterAuthServiceHandler(s server.Server, hdlr AuthServiceHandler, opts .
Delete(ctx context.Context, in *UserIDRequest, out *emptypb.Empty) error
UpdateRoles(ctx context.Context, in *UpdateRolesRequest, out *User) error
Register(ctx context.Context, in *RegisterRequest, out *User) error
Login(ctx context.Context, in *LoginRequest, out *TokenReply) error
Refresh(ctx context.Context, in *RefreshTokenRequest, out *TokenReply) error
Inspect(ctx context.Context, in *TokenRequest, out *User) error
Login(ctx context.Context, in *LoginRequest, out *Token) error
Refresh(ctx context.Context, in *RefreshTokenRequest, out *Token) error
Inspect(ctx context.Context, in *emptypb.Empty, out *JWTClaims) error
}
type AuthService struct {
authService
@ -202,14 +202,14 @@ func (h *authServiceHandler) Register(ctx context.Context, in *RegisterRequest,
return h.AuthServiceHandler.Register(ctx, in, out)
}
func (h *authServiceHandler) Login(ctx context.Context, in *LoginRequest, out *TokenReply) error {
func (h *authServiceHandler) Login(ctx context.Context, in *LoginRequest, out *Token) error {
return h.AuthServiceHandler.Login(ctx, in, out)
}
func (h *authServiceHandler) Refresh(ctx context.Context, in *RefreshTokenRequest, out *TokenReply) error {
func (h *authServiceHandler) Refresh(ctx context.Context, in *RefreshTokenRequest, out *Token) error {
return h.AuthServiceHandler.Refresh(ctx, in, out)
}
func (h *authServiceHandler) Inspect(ctx context.Context, in *TokenRequest, out *User) error {
func (h *authServiceHandler) Inspect(ctx context.Context, in *emptypb.Empty, out *JWTClaims) error {
return h.AuthServiceHandler.Inspect(ctx, in, out)
}

@ -20,10 +20,10 @@ service AuthService {
rpc UpdateRoles(UpdateRolesRequest) returns (User) {}
rpc Register(RegisterRequest) returns (User) {}
rpc Login(LoginRequest) returns (TokenReply) {}
rpc Refresh(RefreshTokenRequest) returns (TokenReply) {}
rpc Login(LoginRequest) returns (Token) {}
rpc Refresh(RefreshTokenRequest) returns (Token) {}
rpc Inspect (TokenRequest) returns (User) {}
rpc Inspect (google.protobuf.Empty) returns (JWTClaims) {}
}
message KeysReply {
@ -32,10 +32,6 @@ message KeysReply {
bytes refreshPubKey = 3;
}
message TokenRequest {
string accessToken = 1;
}
message ListRequest {
uint64 limit = 1;
uint64 offset = 2;
@ -43,10 +39,9 @@ message ListRequest {
message User {
string id = 1;
string type = 2;
string issuer = 3;
map<string, string> metadata = 4;
repeated string scopes = 5;
string username = 2;
string email = 3;
repeated string roles = 4;
}
message UserListReply {
@ -57,6 +52,7 @@ message UserListReply {
}
message UserIDRequest {
// Optional if specified user must be admin
string userId = 1;
}
@ -65,7 +61,7 @@ message UpdateRolesRequest {
repeated string roles = 2;
}
message TokenReply {
message Token {
string accessToken = 1;
int64 accessTokenExpiresAt = 2;
string refreshToken = 3;
@ -86,3 +82,12 @@ message LoginRequest {
message RefreshTokenRequest {
string refreshToken = 1;
}
message JWTClaims {
string id = 1;
string type = 2;
string issuer = 3;
map<string,string> metadata = 4;
repeated string scopes = 5;
repeated string roles = 6;
}

@ -1,4 +1,4 @@
package auth
package auth2
import (
"context"
@ -12,7 +12,6 @@ import (
func init() {
ClientAuthRegistry().Register(newNoopClientPlugin())
ServiceAuthRegistry().Register(newNoopServicePlugin())
RouterAuthRegistry().Register(newNoopRouterPlugin())
}
@ -26,7 +25,7 @@ func (p *noopClientPlugin) String() string {
return "noop"
}
func (p *noopClientPlugin) Flags() []cli.Flag {
func (p *noopClientPlugin) AppendFlags(flags []cli.Flag) []cli.Flag {
return []cli.Flag{}
}
@ -42,6 +41,13 @@ func (p *noopClientPlugin) Health(ctx context.Context) (string, error) {
return "All fine", nil
}
func (p *noopClientPlugin) SetVerifier(v VerifierPlugin) {
}
func (p *noopClientPlugin) ServiceContext(ctx context.Context) (context.Context, error) {
return ctx, nil
}
func (p *noopClientPlugin) Inspect(ctx context.Context) (*User, error) {
return &User{Id: uuid.New().String(), Issuer: p.String()}, nil
}
@ -54,32 +60,6 @@ func (p *noopClientPlugin) Wrapper() server.HandlerWrapper {
}
}
func newNoopServicePlugin() ServerPlugin {
return new(noopServicePlugin)
}
type noopServicePlugin struct{}
func (p *noopServicePlugin) String() string {
return "noop"
}
func (p *noopServicePlugin) Flags() []cli.Flag {
return []cli.Flag{}
}
func (p *noopServicePlugin) Init(cli *cli.Context, service micro.Service) error {
return nil
}
func (p *noopServicePlugin) Stop() error {
return nil
}
func (p *noopServicePlugin) Health(ctx context.Context) (string, error) {
return "All fine", nil
}
func newNoopRouterPlugin() RouterPlugin {
return new(noopRouterPlugin)
}
@ -90,7 +70,7 @@ func (p *noopRouterPlugin) String() string {
return "noop"
}
func (p *noopRouterPlugin) Flags() []cli.Flag {
func (p *noopRouterPlugin) AppendFlags(flags []cli.Flag) []cli.Flag {
return []cli.Flag{}
}

@ -1,4 +1,4 @@
package auth
package auth2
import (
"context"
@ -9,21 +9,12 @@ import (
"go-micro.dev/v4/server"
)
type User struct {
Id string `json:"id,omitempty"`
Type string `json:"type,omitempty"`
Issuer string `json:"issuer,omitempty"`
Metadata map[string]string `json:"metadata,omitempty"`
Scopes []string `json:"scopes,omitempty"`
Roles []string `json:"roles,omitempty"`
}
type registryFuncs interface {
// String returns the name of the plugin
String() string
// Flags returns a list of cli.Flag's for micro.Service
Flags() []cli.Flag
// AppendFlags appends a list of cli.Flag's for micro.Service
AppendFlags(flags []cli.Flag) []cli.Flag
// Init should be executed in micro.Init
Init(cli *cli.Context, service micro.Service) error
@ -35,10 +26,21 @@ type registryFuncs interface {
Health(ctx context.Context) (string, error)
}
type VerifierPlugin interface {
// Verify verifies that the user is allowed to access the request, it MUST handle AnonUser
Verify(ctx context.Context, u *User, req server.Request) error
}
// ClientPlugin is for services that act as client's behind GinRouter
type ClientPlugin interface {
registryFuncs
// Set the Verifier for this Client
SetVerifier(v VerifierPlugin)
// ServiceContext adds the ServiceUser to the context (when using JWT's it will overwrite the Authorization Header)
ServiceContext(ctx context.Context) (context.Context, error)
// Inspect a context
Inspect(ctx context.Context) (*User, error)
@ -46,11 +48,6 @@ type ClientPlugin interface {
Wrapper() server.HandlerWrapper
}
// ServerPlugin is for authservers
type ServerPlugin interface {
registryFuncs
}
// RouterPlugin is for routers that forward the token or do other stuff required by ClientPlugin
type RouterPlugin interface {
registryFuncs

@ -2,11 +2,12 @@ package jwt
import (
"context"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"crypto/ed25519"
"crypto/rsa"
"errors"
"fmt"
"strings"
"time"
"github.com/golang-jwt/jwt/v4"
"github.com/urfave/cli/v2"
@ -14,62 +15,69 @@ import (
"go-micro.dev/v4/metadata"
"go-micro.dev/v4/server"
"jochum.dev/jo-micro/auth2"
"jochum.dev/jo-micro/auth2/internal/util"
"jochum.dev/jo-micro/auth2/plugins/verifier/endpointroles"
"jochum.dev/jo-micro/auth2/shared/sjwt"
"jochum.dev/jo-micro/auth2/shared/sutil"
)
type jWTClaims struct {
*jwt.StandardClaims
Type string `json:"type,omitempty"`
Roles []string `json:"roles,omitempty"`
Scopes []string `json:"scopes,omitempty"`
}
func init() {
auth.ClientAuthRegistry().Register(newJWTPlugin())
auth2.ClientAuthRegistry().Register(newJWTPlugin())
}
func newJWTPlugin() auth.ClientPlugin {
return new(jwtPlugin)
func newJWTPlugin() auth2.ClientPlugin {
return &jwtPlugin{
verifier: endpointroles.NewVerifier(
endpointroles.NoDefaultDeny(),
),
}
}
type jwtPlugin struct {
pubKey any
audiences []string
pubKey any
privKey any
verifier auth2.VerifierPlugin
}
func (p *jwtPlugin) String() string {
return "jwt"
}
func (p *jwtPlugin) Flags() []cli.Flag {
return []cli.Flag{
&cli.StringFlag{
Name: "auth2_jwt_pub_key",
Usage: "Public key PEM base64 encoded",
EnvVars: []string{"MICRO_AUTH2_JWT_PUB_KEY"},
},
}
func (p *jwtPlugin) AppendFlags(flags []cli.Flag) []cli.Flag {
flags = sutil.AppendFlag(flags, &cli.StringFlag{
Name: "auth2_jwt_pub_key",
Usage: "Public key PEM base64 encoded for access keys",
EnvVars: []string{"MICRO_AUTH2_JWT_PUB_KEY"},
})
flags = sutil.AppendFlag(flags, &cli.StringFlag{
Name: "auth2_jwt_priv_key",
Usage: "Private key PEM base64 encoded for access keys",
EnvVars: []string{"MICRO_AUTH2_JWT_PRIV_KEY"},
})
return sutil.AppendFlag(flags, &cli.StringSliceFlag{
Name: "auth2_jwt_audience",
Usage: "Add and expect this JWT audience",
EnvVars: []string{"MICRO_AUTH2_JWT_AUDIENCES"},
})
}
func (p *jwtPlugin) Init(cli *cli.Context, service micro.Service) error {
if len(cli.String("auth2_jwt_pub_key")) < 1 {
return errors.New("you must provide micro-auth-jwt-pub-key")
}
aPub, err := base64.StdEncoding.DecodeString(cli.String("micro-auth-jwt-pub-key"))
if err != nil {
return err
if len(cli.String("auth2_jwt_pub_key")) < 1 || len(cli.String("auth2_jwt_priv_key")) < 1 {
return errors.New("you must provide auth2_jwt_(priv|pub)_key")
}
block, _ := pem.Decode(aPub)
if block == nil {
return errors.New("failed to parse PEM block containing the key")
if cli.StringSlice("auth2_jwt_audience") == nil {
return errors.New("MICRO_AUTH2_JWT_AUDIENCES must be given")
}
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
pub, priv, err := sjwt.DecodeKeyPair(cli.String("auth2_jwt_pub_key"), cli.String("auth2_jwt_priv_key"))
if err != nil {
return err
}
p.audiences = cli.StringSlice("auth2_jwt_audience")
p.pubKey = pub
p.privKey = priv
return nil
}
@ -82,7 +90,51 @@ func (p *jwtPlugin) Health(ctx context.Context) (string, error) {
return "All fine", nil
}
func (p *jwtPlugin) Inspect(ctx context.Context) (*auth.User, error) {
func (p *jwtPlugin) SetVerifier(v auth2.VerifierPlugin) {
p.verifier = v
}
func (p *jwtPlugin) ServiceContext(ctx context.Context) (context.Context, error) {
user := auth2.ServiceUser
// Create the AccessToken
accessClaims := sjwt.JWTClaims{
RegisteredClaims: &jwt.RegisteredClaims{
Issuer: user.Issuer,
Subject: user.Metadata["Subject"],
Audience: p.audiences,
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Duration(10) * time.Second)),
NotBefore: jwt.NewNumericDate(time.Now().Add(-time.Second)),
IssuedAt: jwt.NewNumericDate(time.Now()),
ID: user.Id,
},
Roles: user.Roles,
}
if err := accessClaims.Valid(); err != nil {
return ctx, err
}
var accessToken *jwt.Token
switch p.privKey.(type) {
case *rsa.PrivateKey:
accessToken = jwt.NewWithClaims(jwt.SigningMethodRS512, accessClaims)
case ed25519.PrivateKey:
accessToken = jwt.NewWithClaims(jwt.SigningMethodEdDSA, accessClaims)
}
accessSignedToken, err := accessToken.SignedString(p.privKey)
if err != nil {
return ctx, err
}
md := metadata.Metadata{
"Authorization": fmt.Sprintf("Bearer %s", accessSignedToken),
}
ctx = metadata.MergeContext(ctx, md, true)
return ctx, nil
}
func (p *jwtPlugin) Inspect(ctx context.Context) (*auth2.User, error) {
md, ok := metadata.FromContext(ctx)
if !ok {
return nil, errors.New("failed to extract metadata from context")
@ -93,12 +145,12 @@ func (p *jwtPlugin) Inspect(ctx context.Context) (*auth.User, error) {
return nil, errors.New("failed to get Authorization header from context")
}
aTokenString, _, err := util.ExtractToken(authH)
aTokenString, _, err := sutil.ExtractToken(authH)
if err != nil {
return nil, err
}
claims := jWTClaims{}
claims := sjwt.JWTClaims{}
_, err = jwt.ParseWithClaims(aTokenString, &claims, func(token *jwt.Token) (interface{}, error) {
return p.pubKey, nil
})
@ -107,21 +159,26 @@ func (p *jwtPlugin) Inspect(ctx context.Context) (*auth.User, error) {
}
cMD := map[string]string{
"Audience": claims.Audience,
"Audience": strings.Join(claims.Audience, ","),
"ExpiresAt": fmt.Sprintf("%d", claims.ExpiresAt),
"IssuedAt": fmt.Sprintf("%d", claims.IssuedAt),
"NotBefore": fmt.Sprintf("%d", claims.NotBefore),
"Subject": claims.Subject,
}
return &auth.User{Id: claims.Id, Type: claims.Type, Issuer: claims.Issuer, Metadata: cMD, Scopes: claims.Scopes, Roles: claims.Roles}, nil
return &auth2.User{Id: claims.ID, Type: claims.Type, Issuer: claims.Issuer, Metadata: cMD, Scopes: claims.Scopes, Roles: claims.Roles}, nil
}
func (p *jwtPlugin) Wrapper() server.HandlerWrapper {
return func(h server.HandlerFunc) server.HandlerFunc {
return func(ctx context.Context, req server.Request, rsp interface{}) error {
_, err := p.Inspect(ctx)
u, err := p.Inspect(ctx)
if err != nil {
u = auth2.AnonUser
}
ctx = context.WithValue(ctx, auth2.ContextUserKey{}, u)
if err = p.verifier.Verify(ctx, u, req); err != nil {
return err
}

@ -8,22 +8,17 @@ import (
"errors"
"fmt"
"net/http"
"strings"
"github.com/golang-jwt/jwt/v4"
"github.com/urfave/cli/v2"
"go-micro.dev/v4"
"go-micro.dev/v4/metadata"
"jochum.dev/jo-micro/auth2"
"jochum.dev/jo-micro/auth2/internal/util"
auth "jochum.dev/jo-micro/auth2"
"jochum.dev/jo-micro/auth2/shared/sjwt"
"jochum.dev/jo-micro/auth2/shared/sutil"
)
type jWTClaims struct {
*jwt.StandardClaims
Type string `json:"type,omitempty"`
Roles []string `json:"roles,omitempty"`
Scopes []string `json:"scopes,omitempty"`
}
func init() {
auth.RouterAuthRegistry().Register(newJWTPlugin())
}
@ -40,21 +35,19 @@ func (p *jwtPlugin) String() string {
return "jwt"
}
func (p *jwtPlugin) Flags() []cli.Flag {
return []cli.Flag{
&cli.StringFlag{
Name: "auth2_jwt_pub_key",
Usage: "Public key PEM base64 encoded",
EnvVars: []string{"MICRO_AUTH2_JWT_PUB_KEY"},
},
}
func (p *jwtPlugin) AppendFlags(flags []cli.Flag) []cli.Flag {
return sutil.AppendFlag(flags, &cli.StringFlag{
Name: "auth2_jwt_pub_key",
Usage: "Public key PEM base64 encoded",
EnvVars: []string{"MICRO_AUTH2_JWT_PUB_KEY"},
})
}
func (p *jwtPlugin) Init(cli *cli.Context, service micro.Service) error {
if len(cli.String("auth2_jwt_pub_key")) < 1 {
return errors.New("you must provide micro-auth-jwt-pub-key")
return errors.New("you must provide auth2_jwt_pub_key")
}
aPub, err := base64.StdEncoding.DecodeString(cli.String("micro-auth-jwt-pub-key"))
aPub, err := base64.StdEncoding.DecodeString(cli.String("auth2_jwt_pub_key"))
if err != nil {
return err
}
@ -87,12 +80,12 @@ func (p *jwtPlugin) Inspect(r *http.Request) (*auth.User, error) {
return nil, errors.New("failed to get Authorization header from context")
}
aTokenString, _, err := util.ExtractToken(r.Header.Get("Authorization"))
aTokenString, _, err := sutil.ExtractToken(r.Header.Get("Authorization"))
if err != nil {
return nil, err
}
claims := jWTClaims{}
claims := sjwt.JWTClaims{}
_, err = jwt.ParseWithClaims(aTokenString, &claims, func(token *jwt.Token) (interface{}, error) {
return p.pubKey, nil
})
@ -101,14 +94,14 @@ func (p *jwtPlugin) Inspect(r *http.Request) (*auth.User, error) {
}
cMD := map[string]string{
"Audience": claims.Audience,
"Audience": strings.Join(claims.Audience, ","),
"ExpiresAt": fmt.Sprintf("%d", claims.ExpiresAt),
"IssuedAt": fmt.Sprintf("%d", claims.IssuedAt),
"NotBefore": fmt.Sprintf("%d", claims.NotBefore),
"Subject": claims.Subject,
}
return &auth.User{Id: claims.Id, Type: claims.Type, Issuer: claims.Issuer, Metadata: cMD, Scopes: claims.Scopes, Roles: claims.Roles}, nil
return &auth.User{Id: claims.ID, Type: claims.Type, Issuer: claims.Issuer, Metadata: cMD, Scopes: claims.Scopes, Roles: claims.Roles}, nil
}
func (p *jwtPlugin) ForwardContext(r *http.Request, ctx context.Context) (context.Context, error) {

@ -0,0 +1,23 @@
package endpointroles
type Options struct {
DefaultDeny bool
}
type Option func(o *Options)
func NoDefaultDeny() Option {
return func(o *Options) {
o.DefaultDeny = false
}
}
func NewOptions(opts ...Option) Options {
options := Options{
DefaultDeny: true,
}
for _, o := range opts {
o(&options)
}
return options
}

@ -0,0 +1,49 @@
package endpointroles
import (
"jochum.dev/jo-micro/auth2"
"jochum.dev/jo-micro/auth2/internal/util"
)
// Add this on every Server that exposes RouterClientService
var RouterRule = NewRule(
Endpoint("RouterClientService.Routes"),
RolesAllow([]string{auth2.ROLE_SERVICE}),
)
type Rule struct {
Endpoint string
RolesAllow []string
RolesDeny []string
}
type RuleOption func(e *Rule)
func Endpoint(n interface{}) RuleOption {
return func(e *Rule) {
e.Endpoint = util.ReflectFunctionName(n)
}
}
func RolesAllow(n []string) RuleOption {
return func(e *Rule) {
e.RolesAllow = n
}
}
func RolesDeny(n []string) RuleOption {
return func(e *Rule) {
e.RolesDeny = n
}
}
func NewRule(opts ...RuleOption) Rule {
ep := Rule{
RolesAllow: []string{},
RolesDeny: []string{},
}
for _, o := range opts {
o(&ep)
}
return ep
}

@ -0,0 +1,57 @@
package endpointroles
import (
"context"
"go-micro.dev/v4/errors"
"go-micro.dev/v4/server"
"jochum.dev/jo-micro/auth2"
"jochum.dev/jo-micro/auth2/internal/ilogger"
)
type EndpointRolesVerifier struct {
rules map[string]Rule
options Options
}
func NewVerifier(opts ...Option) *EndpointRolesVerifier {
options := NewOptions(opts...)
return &EndpointRolesVerifier{
rules: make(map[string]Rule, 0),
options: options,
}
}
func (v *EndpointRolesVerifier) AddRules(rules ...Rule) {
for _, rule := range rules {
v.rules[rule.Endpoint] = rule
}
}
func (v *EndpointRolesVerifier) Verify(ctx context.Context, u *auth2.User, req server.Request) error {
if ep, ok := v.rules[req.Endpoint()]; ok {
if auth2.IntersectsRoles(u, ep.RolesDeny...) {
ilogger.Logrus().WithField("endpoint", req.Endpoint()).WithField("rolesDeny", ep.RolesDeny).WithField("userRoles", u.Roles).Debug("Unauthorized")
return errors.Unauthorized("auth2/plugins/verifier/endpointroles/EndpointRolesVerifier.Verify|Denied by rule", "Unauthorized")
}
if auth2.IntersectsRoles(u, ep.RolesAllow...) {
ilogger.Logrus().WithField("endpoint", req.Endpoint()).WithField("rolesAllow", ep.RolesAllow).WithField("userRoles", u.Roles).Trace("Authorized")
// Allowed by role
return nil
}
if v.options.DefaultDeny {
ilogger.Logrus().WithField("endpoint", req.Endpoint()).Debug("DefaultDeny: not in RolesAllow/Deny")
return errors.Unauthorized("auth2/plugins/verifier/endpointroles/EndpointRolesVerifier.Verify|No matching Role", "Unauthorized")
}
}
if !v.options.DefaultDeny {
ilogger.Logrus().WithField("endpoint", req.Endpoint()).Trace("DefaultAllow: no rule")
return nil
}
ilogger.Logrus().WithField("endpoint", req.Endpoint()).Debug("DefaultDeny: no rule")
return errors.Unauthorized("auth2/plugins/verifier/endpointroles/EndpointRolesVerifier.Verify|No rule for EP", "Unauthorized")
}

@ -1,4 +1,4 @@
package auth
package auth2
import (
"context"
@ -7,28 +7,38 @@ import (
"github.com/urfave/cli/v2"
"go-micro.dev/v4"
"jochum.dev/jo-micro/auth2/shared/sutil"
)
var car = &AuthRegistry[ClientPlugin]{kind: "client", plugins: make(map[string]ClientPlugin)}
var sar = &AuthRegistry[ServerPlugin]{kind: "service", plugins: make(map[string]ServerPlugin)}
var rar = &AuthRegistry[RouterPlugin]{kind: "router", plugins: make(map[string]RouterPlugin)}
func ClientAuthRegistry() *AuthRegistry[ClientPlugin] {
return car
}
func ServiceAuthRegistry() *AuthRegistry[ServerPlugin] {
return sar
}
func RouterAuthRegistry() *AuthRegistry[RouterPlugin] {
return rar
}
type AuthRegistry[T any] struct {
kind string
plugin T
plugins map[string]T
forcedPlugin string
kind string
plugin T
plugins map[string]T
}
func (r *AuthRegistry[T]) ForcePlugin(pName string) error {
r.forcedPlugin = pName
m, ok := r.plugins[pName]
if !ok {
return fmt.Errorf("unknown plugin '%s'", pName)
}
r.plugin = m
return nil
}
// Register registers a plugin within AuthRegistry
@ -39,18 +49,19 @@ func (r *AuthRegistry[T]) Register(plugin T) {
}
// Flags returns a list of cli.Flag's for micro.Service
func (r *AuthRegistry[T]) Flags() []cli.Flag {
flags := []cli.Flag{
&cli.StringFlag{
func (r *AuthRegistry[T]) AppendFlags(flags []cli.Flag) []cli.Flag {
if r.forcedPlugin == "" {
flags = sutil.AppendFlag(flags, &cli.StringFlag{
Name: fmt.Sprintf("auth2_%s", r.kind),
Usage: fmt.Sprintf("Auth %s Plugin to use", r.kind),
EnvVars: []string{fmt.Sprintf("MICRO_AUTH2_%s", strings.ToUpper(r.kind))},
Value: "noop",
},
})
}
for _, p := range r.plugins {
if p2, ok := any(p).(registryFuncs); ok {
flags = append(flags, p2.Flags()...)
flags = p2.AppendFlags(flags)
}
}
@ -64,16 +75,17 @@ func (r *AuthRegistry[T]) Plugin() T {
// Init should be executed in micro.Init
func (r *AuthRegistry[T]) Init(cli *cli.Context, service micro.Service) error {
plugin := cli.String(fmt.Sprintf("auth2_%s", r.kind))
if r.forcedPlugin == "" {
plugin := cli.String(fmt.Sprintf("auth2_%s", r.kind))
m, ok := r.plugins[plugin]
if !ok {
return fmt.Errorf("unknown MICRO_AUTH2_%s plugin '%s'", strings.ToUpper(r.kind), plugin)
}
m, ok := r.plugins[plugin]
if !ok {
return fmt.Errorf("unknown MICRO_AUTH2_%s plugin '%s'", strings.ToUpper(r.kind), plugin)
r.plugin = m
}
r.plugin = m
m2, _ := any(m).(registryFuncs)
m2, _ := any(r.plugin).(registryFuncs)
return m2.Init(cli, service)
}

@ -0,0 +1,35 @@
package auth2
const ROLE_SERVICE = "service"
const ROLE_SUPERADMIN = "superadmin"
const ROLE_ADMIN = "admin"
const ROLE_USER = "user"
const ROLE_ANONYMOUS = "anonymous"
var RolesAdmin = []string{ROLE_ADMIN, ROLE_SUPERADMIN}
var RolesUsersAndAdmin = []string{ROLE_USER, ROLE_ADMIN, ROLE_SUPERADMIN}
var RolesServiceAndUsersAndAdmin = []string{ROLE_SERVICE, ROLE_USER, ROLE_ADMIN, ROLE_SUPERADMIN}
var RolesServiceAndAdmin = []string{ROLE_SERVICE, ROLE_ADMIN, ROLE_SUPERADMIN}
var RolesAllAndAnon = []string{ROLE_SERVICE, ROLE_SUPERADMIN, ROLE_ADMIN, ROLE_USER, ROLE_ANONYMOUS}
func HasRole(user *User, role string) bool {
for _, ur := range user.Roles {
if ur == role {
return true
}
}
return false
}
func IntersectsRoles(user *User, roles ...string) bool {
for _, ur := range user.Roles {
for _, mr := range roles {
if ur == mr {
return true
}
}
}
return false
}

@ -0,0 +1,10 @@
package sjwt
import "github.com/golang-jwt/jwt/v4"
type JWTClaims struct {
*jwt.RegisteredClaims
Type string `json:"type,omitempty"`
Roles []string `json:"roles,omitempty"`
Scopes []string `json:"scopes,omitempty"`
}

@ -0,0 +1,42 @@
package sjwt
import (
"crypto/x509"
"encoding/base64"
"encoding/pem"
"fmt"
"go-micro.dev/v4/errors"
)
func DecodeKeyPair(pub string, priv string) (any, any, error) {
b, err := base64.StdEncoding.DecodeString(pub)
if err != nil {
return nil, nil, errors.InternalServerError("shared/sjwt/DecodeKeyPair.base64", fmt.Sprintf("%s", err))
}
block, _ := pem.Decode(b)
if block == nil {
return nil, nil, errors.InternalServerError("shared/sjwt/DecodeKeyPair.pem", "failed to parse PEM block containing the key")
}
pubResult, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, nil, errors.InternalServerError("shared/sjwt/DecodeKeyPair.ParsePKIXPublicKey", fmt.Sprintf("%s", err))
}
b, err = base64.StdEncoding.DecodeString(priv)
if err != nil {
return nil, nil, errors.InternalServerError("shared/sjwt/DecodeKeyPair.base64_priv", fmt.Sprintf("%s", err))
}
block, _ = pem.Decode(b)
if block == nil {
return nil, nil, errors.InternalServerError("shared/sjwt/DecodeKeyPair.pem_priv", "failed to parse PEM block containing the key")
}
privResult, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return nil, nil, errors.InternalServerError("shared/sjwt/DecodeKeyPair.ParsePKCS8PrivateKey", fmt.Sprintf("%s", err))
}
return pubResult, privResult, nil
}

@ -0,0 +1,19 @@
package sutil
import "github.com/urfave/cli/v2"
func AppendFlag(flags []cli.Flag, flag cli.Flag) []cli.Flag {
has := false
for _, f := range flags {
if f.Names()[0] == flag.Names()[0] {
has = true
break
}
}
if has {
return flags
}
return append(flags, flag)
}

@ -1,4 +1,4 @@
package util
package sutil
import (
"errors"

@ -0,0 +1,33 @@
package auth2
type User struct {
Id string `json:"id,omitempty"`
Type string `json:"type,omitempty"`
Issuer string `json:"issuer,omitempty"`
Metadata map[string]string `json:"metadata,omitempty"`
Scopes []string `json:"scopes,omitempty"`
Roles []string `json:"roles,omitempty"`
}
// AnonUser will be used when theres no user
var AnonUser = &User{
Id: "00000000-0000-0000-0000-000000000000",
Type: "user",
Issuer: "nobody",
Metadata: map[string]string{
"Subject": "service",
},
Scopes: []string{},
Roles: []string{ROLE_ANONYMOUS},
}
var ServiceUser = &User{
Id: "00000000-0000-0000-0000-000000000001",
Type: "service",
Issuer: "",
Scopes: []string{},
Roles: []string{ROLE_SERVICE},
}
// ContextUserKey is the key in the context for the User value.
type ContextUserKey struct{}
Loading…
Cancel
Save