github.com/argoproj/argo-cd/v2@v2.10.9/server/session/session.go (about) 1 package session 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/argoproj/argo-cd/v2/util/settings" 8 9 "github.com/google/uuid" 10 "google.golang.org/grpc/codes" 11 "google.golang.org/grpc/status" 12 13 "github.com/argoproj/argo-cd/v2/pkg/apiclient/session" 14 "github.com/argoproj/argo-cd/v2/server/rbacpolicy" 15 util "github.com/argoproj/argo-cd/v2/util/io" 16 sessionmgr "github.com/argoproj/argo-cd/v2/util/session" 17 ) 18 19 // Server provides a Session service 20 type Server struct { 21 mgr *sessionmgr.SessionManager 22 settingsMgr *settings.SettingsManager 23 authenticator Authenticator 24 policyEnf *rbacpolicy.RBACPolicyEnforcer 25 limitLoginAttempts func() (util.Closer, error) 26 } 27 28 type Authenticator interface { 29 Authenticate(ctx context.Context) (context.Context, error) 30 } 31 32 // NewServer returns a new instance of the Session service 33 func NewServer(mgr *sessionmgr.SessionManager, settingsMgr *settings.SettingsManager, authenticator Authenticator, policyEnf *rbacpolicy.RBACPolicyEnforcer, rateLimiter func() (util.Closer, error)) *Server { 34 return &Server{mgr, settingsMgr, authenticator, policyEnf, rateLimiter} 35 } 36 37 // Create generates a JWT token signed by Argo CD intended for web/CLI logins of the admin user 38 // using username/password 39 func (s *Server) Create(_ context.Context, q *session.SessionCreateRequest) (*session.SessionResponse, error) { 40 if s.limitLoginAttempts != nil { 41 closer, err := s.limitLoginAttempts() 42 if err != nil { 43 return nil, err 44 } 45 defer util.Close(closer) 46 } 47 48 if q.Token != "" { 49 return nil, status.Errorf(codes.Unauthenticated, "token-based session creation no longer supported. please upgrade argocd cli to v0.7+") 50 } 51 if q.Username == "" || q.Password == "" { 52 return nil, status.Errorf(codes.Unauthenticated, "no credentials supplied") 53 } 54 err := s.mgr.VerifyUsernamePassword(q.Username, q.Password) 55 if err != nil { 56 return nil, err 57 } 58 uniqueId, err := uuid.NewRandom() 59 if err != nil { 60 return nil, err 61 } 62 argoCDSettings, err := s.settingsMgr.GetSettings() 63 if err != nil { 64 return nil, err 65 } 66 jwtToken, err := s.mgr.Create( 67 fmt.Sprintf("%s:%s", q.Username, settings.AccountCapabilityLogin), 68 int64(argoCDSettings.UserSessionDuration.Seconds()), 69 uniqueId.String()) 70 71 if err != nil { 72 return nil, err 73 } 74 return &session.SessionResponse{Token: jwtToken}, nil 75 } 76 77 // Delete an authentication cookie from the client. This makes sense only for the Web client. 78 func (s *Server) Delete(ctx context.Context, q *session.SessionDeleteRequest) (*session.SessionResponse, error) { 79 return &session.SessionResponse{Token: ""}, nil 80 } 81 82 // AuthFuncOverride overrides the authentication function and let us not require auth to receive auth. 83 // Without this function here, ArgoCDServer.authenticate would be invoked and credentials checked. 84 // Since this service is generally invoked when the user has _no_ credentials, that would create a 85 // chicken-and-egg situation if we didn't place this here to allow traffic to pass through. 86 func (s *Server) AuthFuncOverride(ctx context.Context, fullMethodName string) (context.Context, error) { 87 // this authenticates the user, but ignores any error, so that we have claims populated 88 ctx, _ = s.authenticator.Authenticate(ctx) 89 return ctx, nil 90 } 91 92 func (s *Server) GetUserInfo(ctx context.Context, q *session.GetUserInfoRequest) (*session.GetUserInfoResponse, error) { 93 return &session.GetUserInfoResponse{ 94 LoggedIn: sessionmgr.LoggedIn(ctx), 95 Username: sessionmgr.Username(ctx), 96 Iss: sessionmgr.Iss(ctx), 97 Groups: sessionmgr.Groups(ctx, s.policyEnf.GetScopes()), 98 }, nil 99 }