Gzip JWTs and Adds New User Info Page (#2204)

This commit is contained in:
Alex Collins 2019-09-05 13:31:04 -07:00 committed by GitHub
parent e322750265
commit cbf9585d84
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
44 changed files with 1191 additions and 351 deletions

View file

@ -240,6 +240,7 @@ jobs:
ARGOCD_FAKE_IN_CLUSTER: "true"
ARGOCD_SSH_DATA_PATH: "/tmp/argo-e2e/app/config/ssh"
ARGOCD_TLS_DATA_PATH: "/tmp/argo-e2e/app/config/tls"
ARGOCD_ZJWT_FEATURE_FLAG: "always"
- run:
name: Start Test Git
command: |

View file

@ -186,6 +186,8 @@ start-e2e: cli
# set paths for locally managed ssh known hosts and tls certs data
ARGOCD_SSH_DATA_PATH=/tmp/argo-e2e/app/config/ssh \
ARGOCD_TLS_DATA_PATH=/tmp/argo-e2e/app/config/tls \
ARGOCD_E2E_DISABLE_AUTH=false \
ARGOCD_ZJWT_FEATURE_FLAG=always \
goreman start
# Cleans VSCode debug.test files from sub-dirs to prevent them from being included in packr boxes
@ -204,7 +206,8 @@ start:
docker version
kubectl create ns argocd || true
kubens argocd
goreman start
ARGOCD_ZJWT_FEATURE_FLAG=always \
goreman start
.PHONY: pre-commit
pre-commit: dep-ensure codegen build lint test

View file

@ -1,5 +1,5 @@
controller: sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true go run ./cmd/argocd-application-controller/main.go --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081}"
api-server: sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true go run ./cmd/argocd-server/main.go --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --disable-auth --insecure --dex-server http://localhost:${ARGOCD_E2E_DEX_PORT:-5556} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --port ${ARGOCD_E2E_APISERVER_PORT:-8080} --staticassets ui/dist/app"
api-server: sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true go run ./cmd/argocd-server/main.go --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --disable-auth=${ARGOCD_E2E_DISABLE_AUTH:-'true'} --insecure --dex-server http://localhost:${ARGOCD_E2E_DEX_PORT:-5556} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --port ${ARGOCD_E2E_APISERVER_PORT:-8080} --staticassets ui/dist/app"
dex: sh -c "go run ./cmd/argocd-util/main.go gendexcfg -o `pwd`/dist/dex.yaml && docker run --rm -p ${ARGOCD_E2E_DEX_PORT:-5556}:${ARGOCD_E2E_DEX_PORT:-5556} -v `pwd`/dist/dex.yaml:/dex.yaml quay.io/dexidp/dex:v2.14.0 serve /dex.yaml"
redis: docker run --rm --name argocd-redis -i -p ${ARGOCD_E2E_REDIS_PORT:-6379}:${ARGOCD_E2E_REDIS_PORT:-6379} redis:5.0.3-alpine --save "" --appendonly no --port ${ARGOCD_E2E_REDIS_PORT:-6379}
repo-server: sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true go run ./cmd/argocd-repo-server/main.go --loglevel debug --port ${ARGOCD_E2E_REPOSERVER_PORT:-8081} --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379}"

View file

@ -1494,6 +1494,23 @@
}
}
},
"/api/v1/session/userinfo": {
"get": {
"tags": [
"SessionService"
],
"summary": "Get the current user's info",
"operationId": "GetUserInfo",
"responses": {
"200": {
"description": "(empty)",
"schema": {
"$ref": "#/definitions/sessionGetUserInfoResponse"
}
}
}
}
},
"/api/v1/settings": {
"get": {
"tags": [
@ -2086,6 +2103,28 @@
"repositoryRepoResponse": {
"type": "object"
},
"sessionGetUserInfoResponse": {
"type": "object",
"title": "The current user's userInfo info",
"properties": {
"groups": {
"type": "array",
"items": {
"type": "string"
}
},
"iss": {
"type": "string"
},
"loggedIn": {
"type": "boolean",
"format": "boolean"
},
"username": {
"type": "string"
}
}
},
"sessionSessionCreateRequest": {
"description": "SessionCreateRequest is for logging in.",
"type": "object",

View file

@ -2,16 +2,21 @@ package commands
import (
"context"
"encoding/json"
"fmt"
"os"
"strings"
"syscall"
"github.com/ghodss/yaml"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"golang.org/x/crypto/ssh/terminal"
"github.com/argoproj/argo-cd/errors"
argocdclient "github.com/argoproj/argo-cd/pkg/apiclient"
accountpkg "github.com/argoproj/argo-cd/pkg/apiclient/account"
"github.com/argoproj/argo-cd/pkg/apiclient/session"
"github.com/argoproj/argo-cd/util"
"github.com/argoproj/argo-cd/util/cli"
"github.com/argoproj/argo-cd/util/localconfig"
@ -27,6 +32,7 @@ func NewAccountCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
},
}
command.AddCommand(NewAccountUpdatePasswordCommand(clientOpts))
command.AddCommand(NewAccountGetUserInfoCommand(clientOpts))
return command
}
@ -93,3 +99,48 @@ func NewAccountUpdatePasswordCommand(clientOpts *argocdclient.ClientOptions) *co
command.Flags().StringVar(&newPassword, "new-password", "", "new password you want to update to")
return command
}
func NewAccountGetUserInfoCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
var (
output string
)
var command = &cobra.Command{
Use: "get-user-info",
Short: "Get user info",
Run: func(c *cobra.Command, args []string) {
if len(args) != 0 {
c.HelpFunc()(c, args)
os.Exit(1)
}
conn, client := argocdclient.NewClientOrDie(clientOpts).NewSessionClientOrDie()
defer util.Close(conn)
ctx := context.Background()
response, err := client.GetUserInfo(ctx, &session.GetUserInfoRequest{})
errors.CheckError(err)
switch output {
case "yaml":
yamlBytes, err := yaml.Marshal(response)
errors.CheckError(err)
fmt.Println(string(yamlBytes))
case "json":
jsonBytes, err := json.MarshalIndent(response, "", " ")
errors.CheckError(err)
fmt.Println(string(jsonBytes))
case "":
fmt.Printf("Logged In: %v\n", response.LoggedIn)
if response.LoggedIn {
fmt.Printf("Username: %s\n", response.Username)
fmt.Printf("Issuer: %s\n", response.Iss)
fmt.Printf("Groups: %v\n", strings.Join(response.Groups, ","))
}
default:
log.Fatalf("Unknown output format: %s", output)
}
},
}
command.Flags().StringVarP(&output, "output", "o", "", "Output format. One of: yaml, json")
return command
}

View file

@ -3,23 +3,16 @@
package account // import "github.com/argoproj/argo-cd/pkg/apiclient/account"
import (
fmt "fmt"
import proto "github.com/gogo/protobuf/proto"
import fmt "fmt"
import math "math"
import _ "github.com/gogo/protobuf/gogoproto"
import _ "google.golang.org/genproto/googleapis/api/annotations"
proto "github.com/gogo/protobuf/proto"
import context "golang.org/x/net/context"
import grpc "google.golang.org/grpc"
math "math"
_ "github.com/gogo/protobuf/gogoproto"
_ "google.golang.org/genproto/googleapis/api/annotations"
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
io "io"
)
import io "io"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal

View file

@ -9,33 +9,22 @@ package application // import "github.com/argoproj/argo-cd/pkg/apiclient/applica
Application Service API performs CRUD actions against application resources
*/
import (
fmt "fmt"
import proto "github.com/gogo/protobuf/proto"
import fmt "fmt"
import math "math"
import v1alpha1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
import apiclient "github.com/argoproj/argo-cd/reposerver/apiclient"
import _ "github.com/gogo/protobuf/gogoproto"
import _ "google.golang.org/genproto/googleapis/api/annotations"
import v11 "k8s.io/api/core/v1"
import v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
proto "github.com/gogo/protobuf/proto"
import context "golang.org/x/net/context"
import grpc "google.golang.org/grpc"
math "math"
import github_com_gogo_protobuf_proto "github.com/gogo/protobuf/proto"
v1alpha1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
apiclient "github.com/argoproj/argo-cd/reposerver/apiclient"
_ "github.com/gogo/protobuf/gogoproto"
_ "google.golang.org/genproto/googleapis/api/annotations"
v11 "k8s.io/api/core/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
github_com_gogo_protobuf_proto "github.com/gogo/protobuf/proto"
io "io"
)
import io "io"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal

View file

@ -10,25 +10,17 @@ package certificate // import "github.com/argoproj/argo-cd/pkg/apiclient/certifi
resources.
*/
import (
fmt "fmt"
import proto "github.com/gogo/protobuf/proto"
import fmt "fmt"
import math "math"
import v1alpha1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
import _ "github.com/gogo/protobuf/gogoproto"
import _ "google.golang.org/genproto/googleapis/api/annotations"
proto "github.com/gogo/protobuf/proto"
import context "golang.org/x/net/context"
import grpc "google.golang.org/grpc"
math "math"
v1alpha1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
_ "github.com/gogo/protobuf/gogoproto"
_ "google.golang.org/genproto/googleapis/api/annotations"
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
io "io"
)
import io "io"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal

View file

@ -9,27 +9,18 @@ package cluster // import "github.com/argoproj/argo-cd/pkg/apiclient/cluster"
Cluster Service API performs CRUD actions against cluster resources
*/
import (
fmt "fmt"
import proto "github.com/gogo/protobuf/proto"
import fmt "fmt"
import math "math"
import v1alpha1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
import _ "github.com/gogo/protobuf/gogoproto"
import _ "google.golang.org/genproto/googleapis/api/annotations"
import _ "k8s.io/api/core/v1"
proto "github.com/gogo/protobuf/proto"
import context "golang.org/x/net/context"
import grpc "google.golang.org/grpc"
math "math"
v1alpha1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
_ "github.com/gogo/protobuf/gogoproto"
_ "google.golang.org/genproto/googleapis/api/annotations"
_ "k8s.io/api/core/v1"
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
io "io"
)
import io "io"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal

View file

@ -9,29 +9,19 @@ package project // import "github.com/argoproj/argo-cd/pkg/apiclient/project"
Project Service API performs CRUD actions against project resources
*/
import (
fmt "fmt"
import proto "github.com/gogo/protobuf/proto"
import fmt "fmt"
import math "math"
import v1alpha1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
import _ "github.com/gogo/protobuf/gogoproto"
import _ "google.golang.org/genproto/googleapis/api/annotations"
import v1 "k8s.io/api/core/v1"
import _ "k8s.io/apimachinery/pkg/apis/meta/v1"
proto "github.com/gogo/protobuf/proto"
import context "golang.org/x/net/context"
import grpc "google.golang.org/grpc"
math "math"
v1alpha1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
_ "github.com/gogo/protobuf/gogoproto"
_ "google.golang.org/genproto/googleapis/api/annotations"
v1 "k8s.io/api/core/v1"
_ "k8s.io/apimachinery/pkg/apis/meta/v1"
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
io "io"
)
import io "io"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal

View file

@ -9,29 +9,19 @@ package repository // import "github.com/argoproj/argo-cd/pkg/apiclient/reposito
Repository Service API performs CRUD actions against repository resources
*/
import (
fmt "fmt"
import proto "github.com/gogo/protobuf/proto"
import fmt "fmt"
import math "math"
import v1alpha1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
import apiclient "github.com/argoproj/argo-cd/reposerver/apiclient"
import _ "github.com/gogo/protobuf/gogoproto"
import _ "google.golang.org/genproto/googleapis/api/annotations"
import _ "k8s.io/api/core/v1"
proto "github.com/gogo/protobuf/proto"
import context "golang.org/x/net/context"
import grpc "google.golang.org/grpc"
math "math"
v1alpha1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
apiclient "github.com/argoproj/argo-cd/reposerver/apiclient"
_ "github.com/gogo/protobuf/gogoproto"
_ "google.golang.org/genproto/googleapis/api/annotations"
_ "k8s.io/api/core/v1"
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
io "io"
)
import io "io"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal

View file

@ -9,27 +9,18 @@ package session // import "github.com/argoproj/argo-cd/pkg/apiclient/session"
Session Service API performs CRUD actions against session resources
*/
import (
fmt "fmt"
import proto "github.com/gogo/protobuf/proto"
import fmt "fmt"
import math "math"
import _ "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
import _ "github.com/gogo/protobuf/gogoproto"
import _ "google.golang.org/genproto/googleapis/api/annotations"
import _ "k8s.io/api/core/v1"
proto "github.com/gogo/protobuf/proto"
import context "golang.org/x/net/context"
import grpc "google.golang.org/grpc"
math "math"
_ "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
_ "github.com/gogo/protobuf/gogoproto"
_ "google.golang.org/genproto/googleapis/api/annotations"
_ "k8s.io/api/core/v1"
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
io "io"
)
import io "io"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
@ -56,7 +47,7 @@ func (m *SessionCreateRequest) Reset() { *m = SessionCreateRequest{} }
func (m *SessionCreateRequest) String() string { return proto.CompactTextString(m) }
func (*SessionCreateRequest) ProtoMessage() {}
func (*SessionCreateRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_session_8fc70660de77cae0, []int{0}
return fileDescriptor_session_7576be4936f004e2, []int{0}
}
func (m *SessionCreateRequest) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@ -117,7 +108,7 @@ func (m *SessionDeleteRequest) Reset() { *m = SessionDeleteRequest{} }
func (m *SessionDeleteRequest) String() string { return proto.CompactTextString(m) }
func (*SessionDeleteRequest) ProtoMessage() {}
func (*SessionDeleteRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_session_8fc70660de77cae0, []int{1}
return fileDescriptor_session_7576be4936f004e2, []int{1}
}
func (m *SessionDeleteRequest) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@ -158,7 +149,7 @@ func (m *SessionResponse) Reset() { *m = SessionResponse{} }
func (m *SessionResponse) String() string { return proto.CompactTextString(m) }
func (*SessionResponse) ProtoMessage() {}
func (*SessionResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_session_8fc70660de77cae0, []int{2}
return fileDescriptor_session_7576be4936f004e2, []int{2}
}
func (m *SessionResponse) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@ -194,10 +185,124 @@ func (m *SessionResponse) GetToken() string {
return ""
}
// Get the current user's userInfo info
type GetUserInfoRequest struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *GetUserInfoRequest) Reset() { *m = GetUserInfoRequest{} }
func (m *GetUserInfoRequest) String() string { return proto.CompactTextString(m) }
func (*GetUserInfoRequest) ProtoMessage() {}
func (*GetUserInfoRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_session_7576be4936f004e2, []int{3}
}
func (m *GetUserInfoRequest) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *GetUserInfoRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_GetUserInfoRequest.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalTo(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (dst *GetUserInfoRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_GetUserInfoRequest.Merge(dst, src)
}
func (m *GetUserInfoRequest) XXX_Size() int {
return m.Size()
}
func (m *GetUserInfoRequest) XXX_DiscardUnknown() {
xxx_messageInfo_GetUserInfoRequest.DiscardUnknown(m)
}
var xxx_messageInfo_GetUserInfoRequest proto.InternalMessageInfo
// The current user's userInfo info
type GetUserInfoResponse struct {
LoggedIn bool `protobuf:"varint,1,opt,name=loggedIn,proto3" json:"loggedIn,omitempty"`
Username string `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"`
Iss string `protobuf:"bytes,3,opt,name=iss,proto3" json:"iss,omitempty"`
Groups []string `protobuf:"bytes,4,rep,name=groups" json:"groups,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *GetUserInfoResponse) Reset() { *m = GetUserInfoResponse{} }
func (m *GetUserInfoResponse) String() string { return proto.CompactTextString(m) }
func (*GetUserInfoResponse) ProtoMessage() {}
func (*GetUserInfoResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_session_7576be4936f004e2, []int{4}
}
func (m *GetUserInfoResponse) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *GetUserInfoResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_GetUserInfoResponse.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalTo(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (dst *GetUserInfoResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_GetUserInfoResponse.Merge(dst, src)
}
func (m *GetUserInfoResponse) XXX_Size() int {
return m.Size()
}
func (m *GetUserInfoResponse) XXX_DiscardUnknown() {
xxx_messageInfo_GetUserInfoResponse.DiscardUnknown(m)
}
var xxx_messageInfo_GetUserInfoResponse proto.InternalMessageInfo
func (m *GetUserInfoResponse) GetLoggedIn() bool {
if m != nil {
return m.LoggedIn
}
return false
}
func (m *GetUserInfoResponse) GetUsername() string {
if m != nil {
return m.Username
}
return ""
}
func (m *GetUserInfoResponse) GetIss() string {
if m != nil {
return m.Iss
}
return ""
}
func (m *GetUserInfoResponse) GetGroups() []string {
if m != nil {
return m.Groups
}
return nil
}
func init() {
proto.RegisterType((*SessionCreateRequest)(nil), "session.SessionCreateRequest")
proto.RegisterType((*SessionDeleteRequest)(nil), "session.SessionDeleteRequest")
proto.RegisterType((*SessionResponse)(nil), "session.SessionResponse")
proto.RegisterType((*GetUserInfoRequest)(nil), "session.GetUserInfoRequest")
proto.RegisterType((*GetUserInfoResponse)(nil), "session.GetUserInfoResponse")
}
// Reference imports to suppress errors if they are not otherwise used.
@ -211,6 +316,8 @@ const _ = grpc.SupportPackageIsVersion4
// Client API for SessionService service
type SessionServiceClient interface {
// Get the current user's info
GetUserInfo(ctx context.Context, in *GetUserInfoRequest, opts ...grpc.CallOption) (*GetUserInfoResponse, error)
// Create a new JWT for authentication and set a cookie if using HTTP.
Create(ctx context.Context, in *SessionCreateRequest, opts ...grpc.CallOption) (*SessionResponse, error)
// Delete an existing JWT cookie if using HTTP.
@ -225,6 +332,15 @@ func NewSessionServiceClient(cc *grpc.ClientConn) SessionServiceClient {
return &sessionServiceClient{cc}
}
func (c *sessionServiceClient) GetUserInfo(ctx context.Context, in *GetUserInfoRequest, opts ...grpc.CallOption) (*GetUserInfoResponse, error) {
out := new(GetUserInfoResponse)
err := c.cc.Invoke(ctx, "/session.SessionService/GetUserInfo", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *sessionServiceClient) Create(ctx context.Context, in *SessionCreateRequest, opts ...grpc.CallOption) (*SessionResponse, error) {
out := new(SessionResponse)
err := c.cc.Invoke(ctx, "/session.SessionService/Create", in, out, opts...)
@ -246,6 +362,8 @@ func (c *sessionServiceClient) Delete(ctx context.Context, in *SessionDeleteRequ
// Server API for SessionService service
type SessionServiceServer interface {
// Get the current user's info
GetUserInfo(context.Context, *GetUserInfoRequest) (*GetUserInfoResponse, error)
// Create a new JWT for authentication and set a cookie if using HTTP.
Create(context.Context, *SessionCreateRequest) (*SessionResponse, error)
// Delete an existing JWT cookie if using HTTP.
@ -256,6 +374,24 @@ func RegisterSessionServiceServer(s *grpc.Server, srv SessionServiceServer) {
s.RegisterService(&_SessionService_serviceDesc, srv)
}
func _SessionService_GetUserInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetUserInfoRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SessionServiceServer).GetUserInfo(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/session.SessionService/GetUserInfo",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SessionServiceServer).GetUserInfo(ctx, req.(*GetUserInfoRequest))
}
return interceptor(ctx, in, info, handler)
}
func _SessionService_Create_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(SessionCreateRequest)
if err := dec(in); err != nil {
@ -296,6 +432,10 @@ var _SessionService_serviceDesc = grpc.ServiceDesc{
ServiceName: "session.SessionService",
HandlerType: (*SessionServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "GetUserInfo",
Handler: _SessionService_GetUserInfo_Handler,
},
{
MethodName: "Create",
Handler: _SessionService_Create_Handler,
@ -396,6 +536,85 @@ func (m *SessionResponse) MarshalTo(dAtA []byte) (int, error) {
return i, nil
}
func (m *GetUserInfoRequest) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *GetUserInfoRequest) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if m.XXX_unrecognized != nil {
i += copy(dAtA[i:], m.XXX_unrecognized)
}
return i, nil
}
func (m *GetUserInfoResponse) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *GetUserInfoResponse) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if m.LoggedIn {
dAtA[i] = 0x8
i++
if m.LoggedIn {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i++
}
if len(m.Username) > 0 {
dAtA[i] = 0x12
i++
i = encodeVarintSession(dAtA, i, uint64(len(m.Username)))
i += copy(dAtA[i:], m.Username)
}
if len(m.Iss) > 0 {
dAtA[i] = 0x1a
i++
i = encodeVarintSession(dAtA, i, uint64(len(m.Iss)))
i += copy(dAtA[i:], m.Iss)
}
if len(m.Groups) > 0 {
for _, s := range m.Groups {
dAtA[i] = 0x22
i++
l = len(s)
for l >= 1<<7 {
dAtA[i] = uint8(uint64(l)&0x7f | 0x80)
l >>= 7
i++
}
dAtA[i] = uint8(l)
i++
i += copy(dAtA[i:], s)
}
}
if m.XXX_unrecognized != nil {
i += copy(dAtA[i:], m.XXX_unrecognized)
}
return i, nil
}
func encodeVarintSession(dAtA []byte, offset int, v uint64) int {
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
@ -448,6 +667,41 @@ func (m *SessionResponse) Size() (n int) {
return n
}
func (m *GetUserInfoRequest) Size() (n int) {
var l int
_ = l
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
}
return n
}
func (m *GetUserInfoResponse) Size() (n int) {
var l int
_ = l
if m.LoggedIn {
n += 2
}
l = len(m.Username)
if l > 0 {
n += 1 + l + sovSession(uint64(l))
}
l = len(m.Iss)
if l > 0 {
n += 1 + l + sovSession(uint64(l))
}
if len(m.Groups) > 0 {
for _, s := range m.Groups {
l = len(s)
n += 1 + l + sovSession(uint64(l))
}
}
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
}
return n
}
func sovSession(x uint64) (n int) {
for {
n++
@ -730,6 +984,215 @@ func (m *SessionResponse) Unmarshal(dAtA []byte) error {
}
return nil
}
func (m *GetUserInfoRequest) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowSession
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: GetUserInfoRequest: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: GetUserInfoRequest: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
default:
iNdEx = preIndex
skippy, err := skipSession(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthSession
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *GetUserInfoResponse) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowSession
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: GetUserInfoResponse: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: GetUserInfoResponse: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field LoggedIn", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowSession
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
m.LoggedIn = bool(v != 0)
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Username", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowSession
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthSession
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Username = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Iss", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowSession
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthSession
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Iss = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 4:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Groups", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowSession
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthSession
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Groups = append(m.Groups, string(dAtA[iNdEx:postIndex]))
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipSession(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthSession
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipSession(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
@ -836,32 +1299,38 @@ var (
)
func init() {
proto.RegisterFile("server/session/session.proto", fileDescriptor_session_8fc70660de77cae0)
proto.RegisterFile("server/session/session.proto", fileDescriptor_session_7576be4936f004e2)
}
var fileDescriptor_session_8fc70660de77cae0 = []byte{
// 360 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x91, 0x4f, 0x4b, 0xe3, 0x40,
0x18, 0xc6, 0x99, 0x2e, 0xdb, 0xdd, 0x9d, 0xc3, 0x96, 0x0d, 0x61, 0x0d, 0xa1, 0x16, 0xc9, 0x45,
0x29, 0x98, 0x21, 0x7a, 0x11, 0x2f, 0x82, 0x7a, 0xf1, 0xda, 0xde, 0x0a, 0x1e, 0xa6, 0xc9, 0x4b,
0x3a, 0x36, 0x9d, 0x77, 0x9c, 0x99, 0xc6, 0xbb, 0x5f, 0xc1, 0x2f, 0x25, 0x78, 0x11, 0xfc, 0x02,
0x52, 0xfc, 0x20, 0xd2, 0x49, 0x52, 0xb5, 0x15, 0xf1, 0x94, 0x79, 0xe6, 0x99, 0xfc, 0x9e, 0xf7,
0x0f, 0xed, 0x1a, 0xd0, 0x25, 0x68, 0x66, 0xc0, 0x18, 0x81, 0xb2, 0xf9, 0xc6, 0x4a, 0xa3, 0x45,
0xef, 0x57, 0x2d, 0x43, 0x3f, 0xc7, 0x1c, 0xdd, 0x1d, 0x5b, 0x9e, 0x2a, 0x3b, 0xec, 0xe6, 0x88,
0x79, 0x01, 0x8c, 0x2b, 0xc1, 0xb8, 0x94, 0x68, 0xb9, 0x15, 0x28, 0x4d, 0xed, 0x46, 0xd3, 0x23,
0x13, 0x0b, 0x74, 0x6e, 0x8a, 0x1a, 0x58, 0x99, 0xb0, 0x1c, 0x24, 0x68, 0x6e, 0x21, 0xab, 0xdf,
0x5c, 0xe4, 0xc2, 0x4e, 0xe6, 0xe3, 0x38, 0xc5, 0x19, 0xe3, 0xda, 0x45, 0x5c, 0xb9, 0xc3, 0x7e,
0x9a, 0x31, 0x35, 0xcd, 0x97, 0x3f, 0x1b, 0xc6, 0x95, 0x2a, 0x44, 0xea, 0xe0, 0xac, 0x4c, 0x78,
0xa1, 0x26, 0x7c, 0x03, 0x15, 0x65, 0xd4, 0x1f, 0x56, 0xd5, 0x9e, 0x69, 0xe0, 0x16, 0x06, 0x70,
0x3d, 0x07, 0x63, 0xbd, 0x90, 0xfe, 0x9e, 0x1b, 0xd0, 0x92, 0xcf, 0x20, 0x20, 0x3b, 0x64, 0xef,
0xcf, 0x60, 0xa5, 0x97, 0x9e, 0xe2, 0xc6, 0xdc, 0xa0, 0xce, 0x82, 0x56, 0xe5, 0x35, 0xda, 0xf3,
0xe9, 0x4f, 0x8b, 0x53, 0x90, 0xc1, 0x0f, 0x67, 0x54, 0x22, 0xfa, 0xbf, 0x4a, 0x39, 0x87, 0x02,
0x56, 0x29, 0xd1, 0x2e, 0xed, 0xd4, 0xf7, 0x03, 0x30, 0x0a, 0xa5, 0x81, 0x37, 0x00, 0x79, 0x07,
0x38, 0x78, 0x20, 0xf4, 0x6f, 0xfd, 0x72, 0x08, 0xba, 0x14, 0x29, 0x78, 0x97, 0xb4, 0x5d, 0x95,
0xec, 0x6d, 0xc7, 0xcd, 0xfc, 0x3f, 0x6b, 0x25, 0x0c, 0xd6, 0xed, 0x26, 0x2b, 0x0a, 0x6f, 0x9f,
0x5e, 0xee, 0x5a, 0x7e, 0xd4, 0x71, 0xd3, 0x2e, 0x93, 0x66, 0x8f, 0xc7, 0xa4, 0xef, 0x8d, 0x68,
0xbb, 0xaa, 0x75, 0x13, 0xff, 0xa1, 0x87, 0x2f, 0xf0, 0x5b, 0x0e, 0xff, 0xaf, 0xbf, 0x8e, 0x3f,
0x3d, 0xb9, 0x5f, 0xf4, 0xc8, 0xe3, 0xa2, 0x47, 0x9e, 0x17, 0x3d, 0x32, 0x4a, 0xbe, 0xb1, 0xcd,
0xb4, 0x10, 0x20, 0x6d, 0x03, 0x18, 0xb7, 0xdd, 0xf2, 0x0e, 0x5f, 0x03, 0x00, 0x00, 0xff, 0xff,
0x65, 0x59, 0xd0, 0x9d, 0x88, 0x02, 0x00, 0x00,
var fileDescriptor_session_7576be4936f004e2 = []byte{
// 453 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0xcf, 0x8e, 0xd3, 0x30,
0x10, 0xc6, 0x95, 0x16, 0x4a, 0xd7, 0x48, 0x2c, 0x98, 0x68, 0x89, 0x42, 0xa9, 0xaa, 0x5c, 0x58,
0xad, 0x44, 0xad, 0xc2, 0x05, 0x71, 0x41, 0x02, 0x24, 0xd4, 0x6b, 0x56, 0x5c, 0x56, 0xe2, 0xe0,
0x4d, 0x06, 0xaf, 0xb7, 0x59, 0x8f, 0xb1, 0xdd, 0xec, 0x9d, 0x57, 0xe0, 0x61, 0x78, 0x05, 0x8e,
0x48, 0xbc, 0x00, 0xaa, 0x78, 0x10, 0x14, 0xe7, 0x0f, 0xdb, 0xb4, 0x42, 0x9c, 0xe2, 0x99, 0x2f,
0xfe, 0x7d, 0x9f, 0x35, 0x43, 0x26, 0x16, 0x4c, 0x09, 0x86, 0x59, 0xb0, 0x56, 0xa2, 0x6a, 0xbf,
0x73, 0x6d, 0xd0, 0x21, 0xbd, 0xd3, 0x94, 0x71, 0x28, 0x50, 0xa0, 0xef, 0xb1, 0xea, 0x54, 0xcb,
0xf1, 0x44, 0x20, 0x8a, 0x02, 0x18, 0xd7, 0x92, 0x71, 0xa5, 0xd0, 0x71, 0x27, 0x51, 0xd9, 0x46,
0x4d, 0x56, 0x2f, 0xed, 0x5c, 0xa2, 0x57, 0x33, 0x34, 0xc0, 0xca, 0x05, 0x13, 0xa0, 0xc0, 0x70,
0x07, 0x79, 0xf3, 0xcf, 0x52, 0x48, 0x77, 0xb1, 0x3e, 0x9f, 0x67, 0x78, 0xc5, 0xb8, 0xf1, 0x16,
0x97, 0xfe, 0xf0, 0x2c, 0xcb, 0x99, 0x5e, 0x89, 0xea, 0xb2, 0x65, 0x5c, 0xeb, 0x42, 0x66, 0x1e,
0xce, 0xca, 0x05, 0x2f, 0xf4, 0x05, 0xdf, 0x41, 0x25, 0x39, 0x09, 0x4f, 0xeb, 0xb4, 0x6f, 0x0d,
0x70, 0x07, 0x29, 0x7c, 0x5e, 0x83, 0x75, 0x34, 0x26, 0xe3, 0xb5, 0x05, 0xa3, 0xf8, 0x15, 0x44,
0xc1, 0x2c, 0x38, 0x3e, 0x48, 0xbb, 0xba, 0xd2, 0x34, 0xb7, 0xf6, 0x1a, 0x4d, 0x1e, 0x0d, 0x6a,
0xad, 0xad, 0x69, 0x48, 0x6e, 0x3b, 0x5c, 0x81, 0x8a, 0x86, 0x5e, 0xa8, 0x8b, 0xe4, 0xa8, 0x73,
0x79, 0x07, 0x05, 0x74, 0x2e, 0xc9, 0x53, 0x72, 0xd8, 0xf4, 0x53, 0xb0, 0x1a, 0x95, 0x85, 0xbf,
0x80, 0xe0, 0x26, 0x20, 0x24, 0xf4, 0x3d, 0xb8, 0x0f, 0x16, 0xcc, 0x52, 0x7d, 0xc2, 0xf6, 0xfa,
0x35, 0x79, 0xb8, 0xd5, 0x6d, 0x10, 0x31, 0x19, 0x17, 0x28, 0x04, 0xe4, 0xcb, 0x9a, 0x32, 0x4e,
0xbb, 0x7a, 0xeb, 0x5d, 0x83, 0xde, 0xbb, 0xee, 0x93, 0xa1, 0xb4, 0xb6, 0x49, 0x5e, 0x1d, 0xe9,
0x11, 0x19, 0x09, 0x83, 0x6b, 0x6d, 0xa3, 0x5b, 0xb3, 0xe1, 0xf1, 0x41, 0xda, 0x54, 0xcf, 0xbf,
0x0d, 0xc8, 0xbd, 0x26, 0xf8, 0x29, 0x98, 0x52, 0x66, 0x40, 0x2f, 0xc9, 0xdd, 0x1b, 0x59, 0xe8,
0xe3, 0x79, 0xbb, 0x13, 0xbb, 0xb9, 0xe3, 0xc9, 0x7e, 0xb1, 0x8e, 0x9f, 0xcc, 0xbe, 0xfc, 0xfc,
0xfd, 0x75, 0x10, 0xd3, 0xc8, 0xef, 0x40, 0xb9, 0xe8, 0xb6, 0xac, 0x0a, 0x2a, 0x2b, 0xf8, 0x47,
0x32, 0xaa, 0xa7, 0x45, 0x9f, 0x74, 0xa4, 0x7d, 0x53, 0x8c, 0xa3, 0xbe, 0xdc, 0x99, 0xc4, 0xde,
0x24, 0x4c, 0x0e, 0x7b, 0x26, 0xaf, 0x82, 0x13, 0x7a, 0x46, 0x46, 0xf5, 0x98, 0x76, 0xf1, 0x5b,
0xe3, 0xfb, 0x07, 0xfe, 0x91, 0xc7, 0x3f, 0x38, 0xe9, 0xe3, 0xdf, 0xbc, 0xfe, 0xbe, 0x99, 0x06,
0x3f, 0x36, 0xd3, 0xe0, 0xd7, 0x66, 0x1a, 0x9c, 0x2d, 0xfe, 0x63, 0x91, 0xb3, 0x42, 0x82, 0x72,
0x2d, 0xe0, 0x7c, 0xe4, 0xf7, 0xf6, 0xc5, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x8f, 0xb6, 0x16,
0x68, 0x83, 0x03, 0x00, 0x00,
}

View file

@ -28,6 +28,15 @@ var _ status.Status
var _ = runtime.String
var _ = utilities.NewDoubleArray
func request_SessionService_GetUserInfo_0(ctx context.Context, marshaler runtime.Marshaler, client SessionServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq GetUserInfoRequest
var metadata runtime.ServerMetadata
msg, err := client.GetUserInfo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func request_SessionService_Create_0(ctx context.Context, marshaler runtime.Marshaler, client SessionServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq SessionCreateRequest
var metadata runtime.ServerMetadata
@ -88,6 +97,35 @@ func RegisterSessionServiceHandler(ctx context.Context, mux *runtime.ServeMux, c
// "SessionServiceClient" to call the correct interceptors.
func RegisterSessionServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client SessionServiceClient) error {
mux.Handle("GET", pattern_SessionService_GetUserInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
if cn, ok := w.(http.CloseNotifier); ok {
go func(done <-chan struct{}, closed <-chan bool) {
select {
case <-done:
case <-closed:
cancel()
}
}(ctx.Done(), cn.CloseNotify())
}
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_SessionService_GetUserInfo_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_SessionService_GetUserInfo_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_SessionService_Create_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
@ -150,12 +188,16 @@ func RegisterSessionServiceHandlerClient(ctx context.Context, mux *runtime.Serve
}
var (
pattern_SessionService_GetUserInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "v1", "session", "userinfo"}, ""))
pattern_SessionService_Create_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "session"}, ""))
pattern_SessionService_Delete_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "session"}, ""))
)
var (
forward_SessionService_GetUserInfo_0 = runtime.ForwardResponseMessage
forward_SessionService_Create_0 = runtime.ForwardResponseMessage
forward_SessionService_Delete_0 = runtime.ForwardResponseMessage

View file

@ -9,27 +9,18 @@ package settings // import "github.com/argoproj/argo-cd/pkg/apiclient/settings"
Settings Service API retrieves Argo CD settings
*/
import (
fmt "fmt"
import proto "github.com/gogo/protobuf/proto"
import fmt "fmt"
import math "math"
import v1alpha1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
import oidc "github.com/argoproj/argo-cd/server/settings/oidc"
import _ "github.com/gogo/protobuf/gogoproto"
import _ "google.golang.org/genproto/googleapis/api/annotations"
proto "github.com/gogo/protobuf/proto"
import context "golang.org/x/net/context"
import grpc "google.golang.org/grpc"
math "math"
v1alpha1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
oidc "github.com/argoproj/argo-cd/server/settings/oidc"
_ "github.com/gogo/protobuf/gogoproto"
_ "google.golang.org/genproto/googleapis/api/annotations"
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
io "io"
)
import io "io"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal

View file

@ -9,23 +9,16 @@ package version // import "github.com/argoproj/argo-cd/pkg/apiclient/version"
Version Service API returns the version of the API server.
*/
import (
fmt "fmt"
import proto "github.com/gogo/protobuf/proto"
import fmt "fmt"
import math "math"
import empty "github.com/golang/protobuf/ptypes/empty"
import _ "google.golang.org/genproto/googleapis/api/annotations"
proto "github.com/gogo/protobuf/proto"
import context "golang.org/x/net/context"
import grpc "google.golang.org/grpc"
math "math"
empty "github.com/golang/protobuf/ptypes/empty"
_ "google.golang.org/genproto/googleapis/api/annotations"
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
io "io"
)
import io "io"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal

View file

@ -3,27 +3,21 @@
package v1alpha1
import (
fmt "fmt"
import proto "github.com/gogo/protobuf/proto"
import fmt "fmt"
import math "math"
proto "github.com/gogo/protobuf/proto"
import v11 "k8s.io/api/core/v1"
import v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
math "math"
import k8s_io_apimachinery_pkg_watch "k8s.io/apimachinery/pkg/watch"
v11 "k8s.io/api/core/v1"
import github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
import strings "strings"
import reflect "reflect"
k8s_io_apimachinery_pkg_watch "k8s.io/apimachinery/pkg/watch"
github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys"
strings "strings"
reflect "reflect"
io "io"
)
import io "io"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal

View file

@ -3,27 +3,18 @@
package apiclient // import "github.com/argoproj/argo-cd/reposerver/apiclient"
import (
fmt "fmt"
import proto "github.com/gogo/protobuf/proto"
import fmt "fmt"
import math "math"
import v1alpha1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
import _ "github.com/gogo/protobuf/gogoproto"
import _ "google.golang.org/genproto/googleapis/api/annotations"
import _ "k8s.io/api/core/v1"
proto "github.com/gogo/protobuf/proto"
import context "golang.org/x/net/context"
import grpc "google.golang.org/grpc"
math "math"
v1alpha1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
_ "github.com/gogo/protobuf/gogoproto"
_ "google.golang.org/genproto/googleapis/api/annotations"
_ "k8s.io/api/core/v1"
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
io "io"
)
import io "io"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal

View file

@ -3,7 +3,6 @@ package account
import (
"time"
"github.com/dgrijalva/jwt-go"
log "github.com/sirupsen/logrus"
"golang.org/x/net/context"
"google.golang.org/grpc/codes"
@ -11,7 +10,6 @@ import (
"github.com/argoproj/argo-cd/common"
"github.com/argoproj/argo-cd/pkg/apiclient/account"
jwtutil "github.com/argoproj/argo-cd/util/jwt"
"github.com/argoproj/argo-cd/util/password"
"github.com/argoproj/argo-cd/util/session"
"github.com/argoproj/argo-cd/util/settings"
@ -34,9 +32,9 @@ func NewServer(sessionMgr *session.SessionManager, settingsMgr *settings.Setting
// UpdatePassword updates the password of the local admin superuser.
func (s *Server) UpdatePassword(ctx context.Context, q *account.UpdatePasswordRequest) (*account.UpdatePasswordResponse, error) {
username := getAuthenticatedUser(ctx)
if username != common.ArgoCDAdminUsername {
return nil, status.Errorf(codes.InvalidArgument, "password can only be changed for local users, not user %q", username)
sub := session.Sub(ctx)
if sub != common.ArgoCDAdminUsername {
return nil, status.Errorf(codes.InvalidArgument, "password can only be changed for local users, not user %q", sub)
}
cdSettings, err := s.settingsMgr.GetSettings()
@ -44,7 +42,7 @@ func (s *Server) UpdatePassword(ctx context.Context, q *account.UpdatePasswordRe
return nil, err
}
err = s.sessionMgr.VerifyUsernamePassword(username, q.CurrentPassword)
err = s.sessionMgr.VerifyUsernamePassword(sub, q.CurrentPassword)
if err != nil {
return nil, status.Errorf(codes.InvalidArgument, "current password does not match")
}
@ -61,24 +59,7 @@ func (s *Server) UpdatePassword(ctx context.Context, q *account.UpdatePasswordRe
if err != nil {
return nil, err
}
log.Infof("user '%s' updated password", username)
log.Infof("user '%s' updated password", sub)
return &account.UpdatePasswordResponse{}, nil
}
// getAuthenticatedUser returns the currently authenticated user (via JWT 'sub' field)
func getAuthenticatedUser(ctx context.Context) string {
claimsIf := ctx.Value("claims")
if claimsIf == nil {
return ""
}
claims, ok := claimsIf.(jwt.Claims)
if !ok {
return ""
}
mapClaims, err := jwtutil.MapClaims(claims)
if err != nil {
return ""
}
return jwtutil.GetField(mapClaims, "sub")
}

View file

@ -47,7 +47,7 @@ func newTestAccountServer(ctx context.Context) (*fake.Clientset, *Server, *sessi
})
settingsMgr := settings.NewSettingsManager(ctx, kubeclientset, testNamespace)
sessionMgr := sessionutil.NewSessionManager(settingsMgr, "")
return kubeclientset, NewServer(sessionMgr, settingsMgr), session.NewServer(sessionMgr)
return kubeclientset, NewServer(sessionMgr, settingsMgr), session.NewServer(sessionMgr, nil)
}
func TestUpdatePassword(t *testing.T) {

View file

@ -79,6 +79,7 @@ import (
"github.com/argoproj/argo-cd/util/healthz"
httputil "github.com/argoproj/argo-cd/util/http"
jsonutil "github.com/argoproj/argo-cd/util/json"
"github.com/argoproj/argo-cd/util/jwt/zjwt"
"github.com/argoproj/argo-cd/util/kube"
"github.com/argoproj/argo-cd/util/oidc"
"github.com/argoproj/argo-cd/util/rbac"
@ -426,7 +427,7 @@ func (a *ArgoCDServer) newGRPCServer() *grpc.Server {
sOpts = append(sOpts, grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(
grpc_logrus.StreamServerInterceptor(a.log),
grpc_prometheus.StreamServerInterceptor,
grpc_auth.StreamServerInterceptor(a.authenticate),
grpc_auth.StreamServerInterceptor(a.Authenticate),
grpc_util.UserAgentStreamServerInterceptor(common.ArgoCDUserAgentName, clientConstraint),
grpc_util.PayloadStreamServerInterceptor(a.log, true, func(ctx netCtx.Context, fullMethodName string, servingObject interface{}) bool {
return !sensitiveMethods[fullMethodName]
@ -438,7 +439,7 @@ func (a *ArgoCDServer) newGRPCServer() *grpc.Server {
bug21955WorkaroundInterceptor,
grpc_logrus.UnaryServerInterceptor(a.log),
grpc_prometheus.UnaryServerInterceptor,
grpc_auth.UnaryServerInterceptor(a.authenticate),
grpc_auth.UnaryServerInterceptor(a.Authenticate),
grpc_util.UserAgentUnaryServerInterceptor(common.ArgoCDUserAgentName, clientConstraint),
grpc_util.PayloadUnaryServerInterceptor(a.log, true, func(ctx netCtx.Context, fullMethodName string, servingObject interface{}) bool {
return !sensitiveMethods[fullMethodName]
@ -450,7 +451,7 @@ func (a *ArgoCDServer) newGRPCServer() *grpc.Server {
db := db.NewDB(a.Namespace, a.settingsMgr, a.KubeClientset)
clusterService := cluster.NewServer(db, a.enf, a.Cache)
repoService := repository.NewServer(a.RepoClientset, db, a.enf, a.Cache, a.settingsMgr)
sessionService := session.NewServer(a.sessionMgr)
sessionService := session.NewServer(a.sessionMgr, a)
projectLock := util.NewKeyLock()
applicationService := application.NewServer(a.Namespace, a.KubeClientset, a.AppClientset, a.RepoClientset, a.Cache, kube.KubectlCmd{}, db, a.enf, projectLock, a.settingsMgr)
projectService := project.NewServer(a.Namespace, a.KubeClientset, a.AppClientset, a.enf, projectLock, a.sessionMgr)
@ -479,12 +480,18 @@ func (a *ArgoCDServer) translateGrpcCookieHeader(ctx context.Context, w http.Res
if !a.Insecure {
flags = append(flags, "Secure")
}
cookie, err := httputil.MakeCookieMetadata(common.AuthCookieName, sessionResp.Token, flags...)
if err != nil {
return err
token := sessionResp.Token
if token != "" {
token, err := zjwt.ZJWT(token)
if err != nil {
return err
}
cookie, err := httputil.MakeCookieMetadata(common.AuthCookieName, token, flags...)
if err != nil {
return err
}
w.Header().Set("Set-Cookie", cookie)
}
w.Header().Set("Set-Cookie", cookie)
}
return nil
}
@ -708,7 +715,7 @@ func mustRegisterGWHandler(register registerFunc, ctx context.Context, mux *runt
}
// Authenticate checks for the presence of a valid token when accessing server-side resources.
func (a *ArgoCDServer) authenticate(ctx context.Context) (context.Context, error) {
func (a *ArgoCDServer) Authenticate(ctx context.Context) (context.Context, error) {
if a.DisableAuth {
return ctx, nil
}
@ -758,7 +765,10 @@ func getToken(md metadata.MD) string {
request := http.Request{Header: header}
token, err := request.Cookie(common.AuthCookieName)
if err == nil {
return token.Value
value, err := zjwt.JWT(token.Value)
if err == nil {
return value
}
}
}
return ""

View file

@ -451,7 +451,7 @@ func TestAuthenticate(t *testing.T) {
ctx = metadata.NewIncomingContext(context.Background(), metadata.Pairs(apiclient.MetaDataTokenKey, token))
}
_, err := argocd.authenticate(ctx)
_, err := argocd.Authenticate(ctx)
if testData.errorMsg != "" {
assert.Errorf(t, err, testData.errorMsg)
} else {

View file

@ -12,14 +12,17 @@ import (
// Server provides a Session service
type Server struct {
mgr *sessionmgr.SessionManager
mgr *sessionmgr.SessionManager
authenticator Authenticator
}
type Authenticator interface {
Authenticate(ctx context.Context) (context.Context, error)
}
// NewServer returns a new instance of the Session service
func NewServer(mgr *sessionmgr.SessionManager) *Server {
return &Server{
mgr: mgr,
}
func NewServer(mgr *sessionmgr.SessionManager, authenticator Authenticator) *Server {
return &Server{mgr, authenticator}
}
// Create generates a JWT token signed by Argo CD intended for web/CLI logins of the admin user
@ -52,5 +55,16 @@ func (s *Server) Delete(ctx context.Context, q *session.SessionDeleteRequest) (*
// Since this service is generally invoked when the user has _no_ credentials, that would create a
// chicken-and-egg situation if we didn't place this here to allow traffic to pass through.
func (s *Server) AuthFuncOverride(ctx context.Context, fullMethodName string) (context.Context, error) {
// this authenticates the user, but ignores any error, so that we have claims populated
ctx, _ = s.authenticator.Authenticate(ctx)
return ctx, nil
}
func (s *Server) GetUserInfo(ctx context.Context, q *session.GetUserInfoRequest) (*session.GetUserInfoResponse, error) {
return &session.GetUserInfoResponse{
LoggedIn: sessionmgr.LoggedIn(ctx),
Username: sessionmgr.Username(ctx),
Iss: sessionmgr.Iss(ctx),
Groups: sessionmgr.Groups(ctx),
}, nil
}

View file

@ -3,7 +3,7 @@ option go_package = "github.com/argoproj/argo-cd/pkg/apiclient/session";
// Session Service
//
// Session Service API performs CRUD actions against session resources
// Session Service API performs CRUD actions against session resources
package session;
import "gogoproto/gogo.proto";
@ -27,9 +27,26 @@ message SessionResponse {
string token = 1;
}
// Get the current user's userInfo info
message GetUserInfoRequest {
}
// The current user's userInfo info
message GetUserInfoResponse {
bool loggedIn = 1;
string username = 2;
string iss = 3;
repeated string groups = 4;
}
// SessionService
service SessionService {
// Get the current user's info
rpc GetUserInfo (GetUserInfoRequest) returns (GetUserInfoResponse) {
option (google.api.http).get = "/api/v1/session/userinfo";
}
// Create a new JWT for authentication and set a cookie if using HTTP.
rpc Create(SessionCreateRequest) returns (SessionResponse) {
option (google.api.http) = {

View file

@ -3,15 +3,11 @@
package oidc // import "github.com/argoproj/argo-cd/server/settings/oidc"
import (
fmt "fmt"
import proto "github.com/gogo/protobuf/proto"
import fmt "fmt"
import math "math"
proto "github.com/gogo/protobuf/proto"
math "math"
io "io"
)
import io "io"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal

View file

@ -375,7 +375,7 @@ func EnsureCleanState(t *testing.T) {
FailOnErr(Run("", "kubectl", "create", "ns", DeploymentNamespace()))
FailOnErr(Run("", "kubectl", "label", "ns", DeploymentNamespace(), testingLabel+"=true"))
log.WithFields(log.Fields{"duration": time.Since(start), "name": name, "id": id}).Info("clean state")
log.WithFields(log.Fields{"duration": time.Since(start), "name": name, "id": id, "username": "admin", "password": "password"}).Info("clean state")
}
func RunCli(args ...string) (string, error) {

View file

@ -0,0 +1,21 @@
package e2e
import (
"testing"
"github.com/stretchr/testify/assert"
. "github.com/argoproj/argo-cd/test/e2e/fixture"
)
func TestUserInfo(t *testing.T) {
EnsureCleanState(t)
output, err := RunCli("account", "get-user-info")
assert.NoError(t, err)
assert.Equal(t, `Logged In: true
Username: admin
Issuer: argocd
Groups: `, output)
}

View file

@ -16,7 +16,6 @@
"@types/deepmerge": "^2.2.0",
"@types/git-url-parse": "^9.0.0",
"@types/js-yaml": "^3.11.2",
"@types/jwt-decode": "^2.2.1",
"@types/minimatch": "^3.0.3",
"@types/prop-types": "^15.5.2",
"@types/react": "^16.8.5",
@ -46,7 +45,6 @@
"jscs": "^3.0.7",
"json-merge-patch": "^0.2.3",
"jsondiffpatch": "^0.3.5",
"jwt-decode": "^2.2.0",
"minimatch": "^3.0.4",
"moment": "^2.24.0",
"monaco-editor": "^0.15.6",

View file

@ -9,9 +9,7 @@ import {
PopupManager,
PopupProps,
} from 'argo-ui';
import * as cookie from 'cookie';
import {createBrowserHistory} from 'history';
import * as jwtDecode from 'jwt-decode';
import * as PropTypes from 'prop-types';
import * as React from 'react';
import {Helmet} from 'react-helmet';
@ -25,6 +23,7 @@ import {Provider} from './shared/context';
import {services} from './shared/services';
import requests from './shared/services/requests';
import {hashCode} from './shared/utils';
import userInfo from './user-info';
services.viewPreferences.init();
const bases = document.getElementsByTagName('base');
@ -36,6 +35,7 @@ const routes: {[path: string]: { component: React.ComponentType<RouteComponentPr
'/login': { component: login.component as any, noLayout: true },
'/applications': { component: applications.component },
'/settings': { component: settings.component },
'/user-info': { component: userInfo.component },
'/help': { component: help.component },
};
@ -47,6 +47,10 @@ const navItems = [{
title: 'Manage your repositories, projects, settings',
path: '/settings',
iconClassName: 'argo-icon-settings',
}, {
title: 'User Info',
path: '/user-info',
iconClassName: 'fa fa-user-circle',
}, {
title: 'Read the documentation, and get help and assistance.',
path: '/help',
@ -55,13 +59,10 @@ const navItems = [{
async function isExpiredSSO() {
try {
const token = cookie.parse(document.cookie)['argocd.token'];
if (token) {
const jwtToken = jwtDecode(token) as any;
if (jwtToken.iss && jwtToken.iss !== 'argocd') {
const authSettings = await services.authService.settings();
return (authSettings.dexConfig && authSettings.dexConfig.connectors || []).length > 0 || authSettings.oidcConfig;
}
const {loggedIn, iss} = await services.users.get();
if (loggedIn && iss !== 'argocd') {
const authSettings = await services.authService.settings();
return (authSettings.dexConfig && authSettings.dexConfig.connectors || []).length > 0 || authSettings.oidcConfig;
}
} catch {
return false;
@ -108,20 +109,15 @@ export class App extends React.Component<{}, { popupProps: PopupProps, error: Er
public async componentDidMount() {
this.popupManager.popupProps.subscribe((popupProps) => this.setState({ popupProps }));
const gaSettings = await services.authService.settings().then((item) => item.googleAnalytics || { trackingID: '', anonymizeUsers: true });
const { trackingID, anonymizeUsers } = gaSettings;
const { trackingID, anonymizeUsers } = await services.authService.settings().then((item) => item.googleAnalytics || { trackingID: '', anonymizeUsers: true });
const {loggedIn, username} = await services.users.get();
if (trackingID) {
const ga = await import('react-ga');
ga.initialize(trackingID);
let userId = '';
const trackPageView = () => {
let nextUserId = services.authService.getCurrentUserId();
if (anonymizeUsers) {
nextUserId = hashCode(nextUserId).toString();
}
if (nextUserId !== userId) {
userId = nextUserId;
ga.set({ userId });
if (loggedIn) {
const userId = !anonymizeUsers ? username : hashCode(username).toString();
ga.set({userId});
}
ga.pageview(location.pathname + location.search);
};

View file

@ -1,10 +1,10 @@
import { DataLoader, Page as ArgoPage, Toolbar, Utils } from 'argo-ui';
import {DataLoader, Page as ArgoPage, Toolbar, Utils} from 'argo-ui';
import { parse } from 'cookie';
import * as PropTypes from 'prop-types';
import * as React from 'react';
import { Observable } from 'rxjs';
import { AppContext } from '../context';
import { services } from '../services';
import {Observable} from 'rxjs';
import {AppContext} from '../context';
import {services} from '../services';
export class Page extends React.Component<{ title: string, toolbar?: Toolbar | Observable<Toolbar> }> {
public static contextTypes = {
@ -18,7 +18,8 @@ export class Page extends React.Component<{ title: string, toolbar?: Toolbar | O
toolbar = toolbar || {};
toolbar.tools = [
toolbar.tools,
services.authService.getCurrentUserId() ?
// this is a crummy check, as the token maybe expired, but it is better than flashing user interface
parse(document.cookie)['argocd.token'] ?
<a key='logout' onClick={() => this.goToLogin(true)}>Logout</a> :
<a key='login' onClick={() => this.goToLogin(false)}>Login</a>,
];

View file

@ -340,6 +340,13 @@ export interface AuthSettings {
};
}
export interface UserInfo {
loggedIn: boolean;
username: string;
iss: string;
groups: string[];
}
export type ConnectionStatus = 'Unknown' | 'Successful' | 'Failed';
export const ConnectionStatuses = {

View file

@ -1,6 +1,3 @@
import { parse } from 'cookie';
import * as jwt from 'jwt-decode';
import { AuthSettings } from '../models';
import requests from './requests';
@ -8,11 +5,4 @@ export class AuthService {
public settings(): Promise<AuthSettings> {
return requests.get('/settings').then((res) => res.body as AuthSettings);
}
public getCurrentUserId(): string {
const cookies = parse(document.cookie);
const token = cookies['argocd.token'];
const user: any = token && jwt(token) || null;
return (user && (user.email || user.sub)) || '';
}
}

View file

@ -1,3 +1,4 @@
import {UserInfo} from '../models';
import requests from './requests';
export class UserService {
@ -8,4 +9,8 @@ export class UserService {
public logout(): Promise<boolean> {
return requests.delete('/session').then((res) => true);
}
public get(): Promise<UserInfo> {
return requests.get('/session/userinfo').then((res) => res.body as UserInfo);
}
}

View file

@ -0,0 +1,10 @@
import * as React from 'react';
import { Route, RouteComponentProps, Switch } from 'react-router';
import { UserInfoOverview } from './user-info-overview/user-info-overview';
export const UserInfoContainer = (props: RouteComponentProps<any>) => (
<Switch>
<Route exact={true} path={`${props.match.path}`} component={UserInfoOverview}/>
</Switch>
);

View file

@ -0,0 +1,7 @@
@import 'node_modules/argo-ui/src/app/shared/styles/config';
.user-info-overview {
&__panel {
margin: 18px 0;
}
}

View file

@ -0,0 +1,34 @@
import * as React from 'react';
import {DataLoader, Page} from '../../../shared/components';
import {services} from '../../../shared/services';
require('./user-info-overview.scss');
export const UserInfoOverview = () => (
<Page title='User Info' toolbar={{breadcrumbs: [{title: 'User Info'}]}}>
<div className='user-info'>
<div className='argo-container'>
<div className='user-info-overview__panel white-box'>
<DataLoader key='userInfo' load={() => services.users.get()}>{(userInfo) => (
userInfo.loggedIn ? (
<React.Fragment key='userInfoInner'>
<p key='username'>Username: {userInfo.username}</p>
<p key='iss'>Issuer: {userInfo.iss}</p>
{userInfo.groups && (<React.Fragment key='userInfo4'><p>Groups:</p>
<ul>
{userInfo.groups.map((group) => (
<li key={group}>{group}</li>
))}
</ul>
</React.Fragment>)}
</React.Fragment>
) : (
<p key='loggedOutMessage'>You are not logged in</p>
)
)}</DataLoader>
</div>
</div>
</div>
</Page>
);

View file

@ -0,0 +1,5 @@
import { UserInfoContainer } from './components/user-info-container';
export default {
component: UserInfoContainer,
};

View file

@ -431,11 +431,6 @@
resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-3.12.1.tgz#5c6f4a1eabca84792fbd916f0cb40847f123c656"
integrity sha512-SGGAhXLHDx+PK4YLNcNGa6goPf9XRWQNAUUbffkwVGGXIxmDKWyGGL4inzq2sPmExu431Ekb9aEMn9BkPqEYFA==
"@types/jwt-decode@^2.2.1":
version "2.2.1"
resolved "https://registry.yarnpkg.com/@types/jwt-decode/-/jwt-decode-2.2.1.tgz#afdf5c527fcfccbd4009b5fd02d1e18241f2d2f2"
integrity sha512-aWw2YTtAdT7CskFyxEX2K21/zSDStuf/ikI3yBqmwpwJF0pS+/IX5DWv+1UFffZIbruP6cnT9/LAJV1gFwAT1A==
"@types/minimatch@*", "@types/minimatch@^3.0.3":
version "3.0.3"
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
@ -5213,11 +5208,6 @@ jsprim@^1.2.2:
json-schema "0.2.3"
verror "1.10.0"
jwt-decode@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/jwt-decode/-/jwt-decode-2.2.0.tgz#7d86bd56679f58ce6a84704a657dd392bba81a79"
integrity sha1-fYa9VmefWM5qhHBKZX3TkruoGnk=
killable@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892"

View file

@ -88,7 +88,7 @@ func IsMember(claims jwtgo.Claims, groups []string) bool {
}
// TODO: groups is hard-wired but we should really be honoring the 'scopes' section in argocd-rbac-cm.
// O(n^2) loop
for _, userGroup := range GetScopeValues(mapClaims, []string{"groups"}) {
for _, userGroup := range GetGroups(mapClaims) {
for _, group := range groups {
if userGroup == group {
return true
@ -97,3 +97,7 @@ func IsMember(claims jwtgo.Claims, groups []string) bool {
}
return false
}
func GetGroups(mapClaims jwtgo.MapClaims) []string {
return GetScopeValues(mapClaims, []string{"groups"})
}

View file

@ -31,3 +31,8 @@ func TestIsMember(t *testing.T) {
assert.False(t, IsMember(jwt.MapClaims{"groups": []string{"my-group"}}, []string{""}))
assert.True(t, IsMember(jwt.MapClaims{"groups": []string{"my-group"}}, []string{"my-group"}))
}
func TestGetGroups(t *testing.T) {
assert.Empty(t, GetGroups(jwt.MapClaims{}))
assert.Equal(t, []string{"foo"}, GetGroups(jwt.MapClaims{"groups": []string{"foo"}}))
}

110
util/jwt/zjwt/zjwt.go Normal file
View file

@ -0,0 +1,110 @@
// The package provides a way to create compact JWTs, "zJWT".
//
// zJWTs for JWT with a large payload can be 1/3 the size of the original.
// This is achieved by gzipping the payload before base 64 encoding it.
//
// zJWTs are only compact if they are smaller than the original JWTs.
// as long as they are smaller than the zJWT representation.
//
// To help differentiate, zJWTs start with "zJWT/v1:"
package zjwt
import (
"bytes"
"compress/gzip"
"encoding/base64"
"fmt"
"io/ioutil"
"os"
"strings"
)
var encoding = base64.RawStdEncoding
// some magic text that is easy to search the Internet for and find your way to docs
var magicNumber = "zJWT/v1"
// when to use ZJWT
// - "never" - never use it - good for it goes wrong
// - "" - when better
// - "always" - always use it - good for forcing this on for testing
var featureFlag = os.Getenv("ARGOCD_ZJWT_FEATURE_FLAG")
// the smallest size JWT we'll compress, 3k chosen as cookies max out at 4k
var minSize = 3000
// ZJWT turns a JWT into either a zJWT or return the original JWT, whichever is smaller.
func ZJWT(text string) (string, error) {
if featureFlag == "never" || featureFlag != "always" && len(text) < minSize {
return text, nil
}
parts := strings.SplitN(text, ".", 3)
if len(parts) != 3 {
return "", fmt.Errorf("JWT '%s' should have 3 dot-delimited parts", text)
}
header := parts[0]
payload := parts[1]
signature := parts[2]
decodedPayload, err := encoding.DecodeString(payload)
if err != nil {
return "", err
}
var buf bytes.Buffer
w := gzip.NewWriter(&buf)
_, err = w.Write(decodedPayload)
if err != nil {
return "", err
}
err = w.Flush()
if err != nil {
return "", err
}
err = w.Close()
if err != nil {
return "", err
}
compressedPayload := encoding.EncodeToString(buf.Bytes())
zJWT := fmt.Sprintf("%s.%s.%s.%s", magicNumber, header, compressedPayload, signature)
if featureFlag == "always" || len(zJWT) < len(text) {
return zJWT, nil
} else {
return text, nil
}
}
// JWT expands either a zJWT or a JWT to a JWT.
func JWT(text string) (string, error) {
parts := strings.SplitN(text, ".", 4)
if len(parts) == 3 {
return text, nil
}
if len(parts) != 4 {
return "", fmt.Errorf("zJWT '%s' should have 4 dot-delimited parts", text)
}
part0 := parts[0]
if part0 != magicNumber {
return "", fmt.Errorf("the first part of the zJWT '%s' does not equal '%s'", part0, magicNumber)
}
header := parts[1]
payload := parts[2]
signature := parts[3]
decodedPayload, err := encoding.DecodeString(payload)
if err != nil {
return "", err
}
r, err := gzip.NewReader(bytes.NewReader(decodedPayload))
if err != nil {
return "", err
}
uncompressedPayload, err := ioutil.ReadAll(r)
if err != nil {
return "", err
}
err = r.Close()
if err != nil {
return "", err
}
encodedPayload := encoding.EncodeToString(uncompressedPayload)
jwt := fmt.Sprintf("%s.%s.%s", header, encodedPayload, signature)
return jwt, nil
}

View file

@ -0,0 +1,49 @@
package zjwt
import (
"testing"
"github.com/stretchr/testify/assert"
)
func init() {
minSize = 0
}
func TestCompactor(t *testing.T) {
t.Run("Small", func(t *testing.T) {
jwt := `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.EpM5XBzTJZ4J8AfoJEcJrjth8pfH28LWdjLo90sYb9g`
compactJWT, err := ZJWT(jwt)
assert.NoError(t, err)
expandedJWT, err := JWT(compactJWT)
assert.NoError(t, err)
assert.Equal(t, jwt, expandedJWT)
assert.Equal(t, jwt, compactJWT)
assert.Equal(t, 100, 100*len(compactJWT)/len(jwt))
})
t.Run("Large", func(t *testing.T) {
jwt := `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJncm91cHMiOlsiU0JHIiwiU0JHOk1lbWJlcnMiLCJTQkc6dWkiLCJTQkc6emlvbiIsIlNCRzpoYXJtb255LXVpLWNvbXBvbmVudHMtZXh0ZW5kZWQiLCJTQkc6bmV4Z2VuLXNlcnZpY2VzLXRlYW0iLCJTQkc6c2JnLXFhLXdyaXRlIiwiU0JHOmFkbWluLXFiYS11aS1hdXRvbWF0aW9uIiwiU0JHOnNiZy9xYm8tYXV0b21hdGlvbi10ZWFtLWFkbWluIiwiU0JHOmdpdGxhYi10b29scy13cml0ZSIsIlNCRzpTQkctT2ZmZXJpbmdzLVFFIiwiU0JHOnFiby1iaWxsaW5nLXRlc3QtcWUtdGVhbSIsIlNCRzpxYm8tYmlsbGluZy10ZXN0LWFkbWluIiwiU0JHOnFiYS1xdWFsaXR5LXRlYW0iLCJTQkc6cWJvLWZ0dS1xdWFsaXR5LWFkbWluLXRlYW0iLCJTQkc6cWJhLW1pZ3JhdGlvbi10b29scy10ZWFtIiwiU0JHOlhjZWxsZW5jZUZvcnVtSlMiLCJTQkc6dHJpbml0eWpzLW1vYmlsZSIsIm1vbmV5LWFuZC1tYWdpYyIsIm1vbmV5LWFuZC1tYWdpYzpPd25lcnMiLCJtb25leS1hbmQtbWFnaWM6TSAmIE0gU2NydW0gVGVhbSIsInBheXJvbGwiLCJwYXlyb2xsOkRFUFJFQ0FURURfT3duZXJzIiwicGF5cm9sbDpQYXlyb2xsQWxsIiwiU0JHLVBDUy1DSUNEIiwiU0JHLVBDUy1DSUNEOk93bmVycyIsIlNCLVFCTy1RRS1PZmZlcmluZ3MiLCJTQi1RQk8tUUUtT2ZmZXJpbmdzOk93bmVycyIsIlNCLVFCTy1RRS1PZmZlcmluZ3M6cWJvLWxxYS1hZG1pbiIsIlNCLVFCTy1RRS1PZmZlcmluZ3M6UUUtR3JvdXAiLCJTQi1RQk8tUUUtUGF5bWVudHMiLCJTQi1RQk8tUUUtUGF5bWVudHM6T3duZXJzIiwiU0ItUUJPLVFFLVBheW1lbnRzOnFiby1wYXltZW50cy1xZS10ZWFtIiwiU0ItUUJPLVFFLVBheXJvbGwiLCJTQi1RQk8tUUUtUGF5cm9sbDpPd25lcnMiLCJTQi1RQk8tUUUtUGF5cm9sbDpTQi1RQk8tUUUtUGF5cm9sbCIsIlNCLVFCTy1RRS1QYXlyb2xsOnBheXJvbGwtcWUtdGVhbSIsIml0YWciLCJpdGFnOml0YWctdWkiLCJpdGFnOml0YWctd3MiLCJpdGFnOm1hcnRpbmktanMiLCJnaXRsYWItbWlncmF0aW9uLTAwMDEiLCJnaXRsYWItbWlncmF0aW9uLTAwMDE6T3duZXJzIiwiZ2l0bGFiLW1pZ3JhdGlvbi0wMDAyIiwiZ2l0bGFiLW1pZ3JhdGlvbi0wMDAyOk93bmVycyIsImdpdGxhYi1taWdyYXRpb24tMDA0NSIsImdpdGxhYi1taWdyYXRpb24tMDA0NTpPd25lcnMiLCJnaXRsYWItbWlncmF0aW9uLTAwNDYiLCJnaXRsYWItbWlncmF0aW9uLTAwNDY6T3duZXJzIiwiU0JHLVBsdWdpbnMiLCJTQkctUGx1Z2luczpDb3JlIiwiU0JHLVBsdWdpbnM6aW1wcm92ZWQtaW52ZW50b3J5IiwiU0JHLVBsdWdpbnM6d2ludm9pY2UtZ21haWwiLCJBbHRpbWV0cmlrIiwiQWx0aW1ldHJpazpBbHRpbWV0cmlrIiwiU0ItUUJPLVFFLU9mZmVyaW5ncy1Nb2JpbGUiLCJTQi1RQk8tUUUtT2ZmZXJpbmdzLU1vYmlsZTpPd25lcnMiLCJRQk8tQ29yZSIsIlFCTy1Db3JlOnFiby1qYXZhLW1vbm9saXRoLXdyaXRlLWFjY2VzcyIsIlFCTy1JbnZlbnRvcnkiLCJRQk8tSW52ZW50b3J5OkFkbWlucyIsIlFCTy1JbnZlbnRvcnk6Q29udHJpYnV0b3JzIiwiUUJPLUludmVudG9yeTpDSUNEIiwiUUJPLUJpbGxpbmciLCJRQk8tQmlsbGluZzpCaWxsaW5nLVVJLUFkbWluIiwiU0JHLVFFIiwiZmFicmljLWFwcC1zaGVsbHMiLCJmYWJyaWMtYXBwLXNoZWxsczpNb2JpbGUgU2hlbGwiLCJmYWJyaWMtYXBwLXVpLWNvbXBvbmVudHMiLCJmYWJyaWMtYXBwLXVpLWNvbXBvbmVudHM6ZmFicmljLWFwcC11aS1jb21wb25lbnRzLW1lbWJlcnMiLCJmYWJyaWMtYXBwLXVpLWNvbXBvbmVudHM6SURTIEV4dGVuZGVkIENvcmUgVGVhbSIsImRldi10ZXN0IiwiZGV2LXRlc3Q6VEVQIiwidGVzdC1wbGF0Zm9ybSIsInRlc3QtcGxhdGZvcm06dGVzdC1wbGF0Zm9ybS1vcmctYWRtaW5zIiwidGVzdC1wbGF0Zm9ybTpvdmVyd2F0Y2gtY29yZSIsIm9wZW4tdWktY29tcG9uZW50cyIsIlNCU0VHLUVQSUMiLCJhY2NvdW50aW5nLWNvcmUiLCJhY2NvdW50aW5nLWNvcmU6YWNjb3VudGluZy1jb3JlLXFiby1jYXNlY2VudGVyLXVpIiwia3ViZXJuZXRlcyIsImt1YmVybmV0ZXM6c2Jnc2VnLWNkcC10ZWFtIiwic3ZjLXNic2VnLWNkcCIsIlNVRFMiLCJTVURTOlNVRFMiLCJhcHAtc2hlbGwiLCJhcHAtc2hlbGw6YXJnb2NkLWFkbWlucyIsIlNCRy1UcmlhZ2VCb3QiLCJzYW5kYm94LXNhbmRib3giLCJzYW5kYm94LXNhbmRib3g6dXgtd29ya3Nob3AtcmFqIiwic2FuZGJveC1zYW5kYm94OnV4LXdzLXJhaiIsInNhbmRib3gtc2FuZGJveDpyYWotdGVzdC13cyIsInBheXJvbGwtcGF5Y2hlY2siLCJwYXlyb2xsLXBheWNoZWNrOlNCR1NDVEVQIiwiYXBwLXVpY29tcG9uZW50cyIsImFwcC11aWNvbXBvbmVudHM6UGxheWdyb3VuZC1ydmFzaWthcmxhIiwiYXBwLXVpY29tcG9uZW50czphcHAtdWljb21wb25lbnRzLWlkcy1kYXNoYm9hcmQtdWkiLCJhcHAtdWljb21wb25lbnRzOmlkcy1wbGF5Z3JvdW5kLXVpIiwiVVgtSW5mcmEiLCJVWC1JbmZyYTpDb3JlIiwiZGVzaWduLXN5c3RlbXMiXX0.XDozAEiz9AIVkA3DFbPOKG6msM43gT5zup3oxsHg_4Q`
compactJWT, err := ZJWT(jwt)
assert.NoError(t, err)
expandedJWT, err := JWT(compactJWT)
assert.NoError(t, err)
assert.Equal(t, jwt, expandedJWT)
assert.Equal(t, 37, 100*len(compactJWT)/len(jwt))
})
}
func TestCompact(t *testing.T) {
_, err := ZJWT(".")
assert.Error(t, err)
}
func TestExpand(t *testing.T) {
_, err := JWT(".")
assert.Error(t, err)
_, err = JWT("...")
assert.Error(t, err)
_, err = JWT("zJWT/v1:...")
assert.Error(t, err)
_, err = JWT("zJWT/v1:..!.")
assert.Error(t, err)
}

View file

@ -20,6 +20,7 @@ import (
"github.com/argoproj/argo-cd/util/cache"
"github.com/argoproj/argo-cd/util/dex"
httputil "github.com/argoproj/argo-cd/util/http"
"github.com/argoproj/argo-cd/util/jwt/zjwt"
"github.com/argoproj/argo-cd/util/rand"
"github.com/argoproj/argo-cd/util/settings"
)
@ -249,13 +250,20 @@ func (a *ClientApp) HandleCallback(w http.ResponseWriter, r *http.Request) {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
cookie, err := httputil.MakeCookieMetadata(common.AuthCookieName, idTokenRAW, flags...)
if err != nil {
claimsJSON, _ := json.Marshal(claims)
http.Error(w, fmt.Sprintf("claims=%s, err=%v", claimsJSON, err), http.StatusInternalServerError)
return
if idTokenRAW != "" {
idTokenRAW, err = zjwt.ZJWT(idTokenRAW)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
cookie, err := httputil.MakeCookieMetadata(common.AuthCookieName, idTokenRAW, flags...)
if err != nil {
claimsJSON, _ := json.Marshal(claims)
http.Error(w, fmt.Sprintf("claims=%s, err=%v", claimsJSON, err), http.StatusInternalServerError)
return
}
w.Header().Set("Set-Cookie", cookie)
}
w.Header().Set("Set-Cookie", cookie)
claimsJSON, _ := json.Marshal(claims)
log.Infof("Web login successful. Claims: %s", claimsJSON)

View file

@ -8,7 +8,7 @@ import (
"os"
"time"
jwt "github.com/dgrijalva/jwt-go"
"github.com/dgrijalva/jwt-go"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
@ -197,16 +197,16 @@ func (mgr *SessionManager) provider() (oidcutil.Provider, error) {
return mgr.prov, nil
}
func LoggedIn(ctx context.Context) bool {
return Sub(ctx) != ""
}
// Username is a helper to extract a human readable username from a context
func Username(ctx context.Context) string {
claims, ok := ctx.Value("claims").(jwt.Claims)
mapClaims, ok := mapClaims(ctx)
if !ok {
return ""
}
mapClaims, err := jwtutil.MapClaims(claims)
if err != nil {
return ""
}
switch jwtutil.GetField(mapClaims, "iss") {
case SessionManagerClaimsIssuer:
return jwtutil.GetField(mapClaims, "sub")
@ -214,3 +214,39 @@ func Username(ctx context.Context) string {
return jwtutil.GetField(mapClaims, "email")
}
}
func Iss(ctx context.Context) string {
mapClaims, ok := mapClaims(ctx)
if !ok {
return ""
}
return jwtutil.GetField(mapClaims, "iss")
}
func Sub(ctx context.Context) string {
mapClaims, ok := mapClaims(ctx)
if !ok {
return ""
}
return jwtutil.GetField(mapClaims, "sub")
}
func Groups(ctx context.Context) []string {
mapClaims, ok := mapClaims(ctx)
if !ok {
return nil
}
return jwtutil.GetGroups(mapClaims)
}
func mapClaims(ctx context.Context) (jwt.MapClaims, bool) {
claims, ok := ctx.Value("claims").(jwt.Claims)
if !ok {
return nil, false
}
mapClaims, err := jwtutil.MapClaims(claims)
if err != nil {
return nil, false
}
return mapClaims, true
}

View file

@ -1,17 +1,17 @@
package session_test
package session
import (
"context"
"testing"
jwt "github.com/dgrijalva/jwt-go"
"github.com/dgrijalva/jwt-go"
"github.com/stretchr/testify/assert"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/fake"
"github.com/argoproj/argo-cd/errors"
"github.com/argoproj/argo-cd/util/password"
sessionutil "github.com/argoproj/argo-cd/util/session"
"github.com/argoproj/argo-cd/util/settings"
)
@ -43,7 +43,7 @@ func TestSessionManager(t *testing.T) {
})
settingsMgr := settings.NewSettingsManager(context.Background(), kubeclientset, "argocd")
mgr := sessionutil.NewSessionManager(settingsMgr, "")
mgr := NewSessionManager(settingsMgr, "")
token, err := mgr.Create(defaultSubject, 0)
if err != nil {
@ -61,3 +61,30 @@ func TestSessionManager(t *testing.T) {
t.Errorf("Token claim subject \"%s\" does not match expected subject \"%s\".", subject, defaultSubject)
}
}
var loggedOutContext = context.Background()
var loggedInContext = context.WithValue(context.Background(), "claims", &jwt.MapClaims{"iss": "qux", "sub": "foo", "email": "bar", "groups": []string{"baz"}})
func TestIss(t *testing.T) {
assert.Empty(t, Iss(loggedOutContext))
assert.Equal(t, "qux", Iss(loggedInContext))
}
func TestLoggedIn(t *testing.T) {
assert.False(t, LoggedIn(loggedOutContext))
assert.True(t, LoggedIn(loggedInContext))
}
func TestUsername(t *testing.T) {
assert.Empty(t, Username(loggedOutContext))
assert.Equal(t, "bar", Username(loggedInContext))
}
func TestSub(t *testing.T) {
assert.Empty(t, Sub(loggedOutContext))
assert.Equal(t, "foo", Sub(loggedInContext))
}
func TestGroups(t *testing.T) {
assert.Empty(t, Groups(loggedOutContext))
assert.Equal(t, []string{"baz"}, Groups(loggedInContext))
}