@@ -2,25 +2,11 @@ package services
22
33import (
44 "context"
5- "crypto"
6- "crypto/rand"
75 "crypto/rsa"
8- "crypto/sha256"
9- "crypto/x509"
10- "encoding/base64"
11- "encoding/hex"
12- "encoding/pem"
13- "slices"
14- "strings"
156 "time"
167
17- "github.com/shellhub-io/shellhub/pkg/api/authorizer"
18- "github.com/shellhub-io/shellhub/pkg/api/jwttoken"
198 "github.com/shellhub-io/shellhub/pkg/api/requests"
20- "github.com/shellhub-io/shellhub/pkg/clock"
219 "github.com/shellhub-io/shellhub/pkg/models"
22- "github.com/shellhub-io/shellhub/pkg/uuid"
23- log "github.com/sirupsen/logrus"
2410)
2511
2612type AuthService interface {
@@ -68,292 +54,23 @@ func (s *service) AuthDevice(ctx context.Context, req requests.DeviceAuth, remot
6854}
6955
7056func (s * service ) AuthLocalUser (ctx context.Context , req * requests.AuthLocalUser , sourceIP string ) (* models.UserAuthResponse , int64 , string , error ) {
71- if s , err := s .store .SystemGet (ctx ); err != nil || ! s .Authentication .Local .Enabled {
72- return nil , 0 , "" , NewErrAuthMethodNotAllowed (models .UserAuthMethodLocal .String ())
73- }
74-
75- var err error
76- var user * models.User
77-
78- if req .Identifier .IsEmail () {
79- user , err = s .store .UserGetByEmail (ctx , strings .ToLower (string (req .Identifier )))
80- } else {
81- user , err = s .store .UserGetByUsername (ctx , strings .ToLower (string (req .Identifier )))
82- }
83-
84- if err != nil {
85- return nil , 0 , "" , NewErrAuthUnathorized (nil )
86- }
87-
88- if ! slices .Contains (user .Preferences .AuthMethods , models .UserAuthMethodLocal ) {
89- return nil , 0 , "" , NewErrAuthUnathorized (nil )
90- }
91-
92- switch user .Status {
93- case models .UserStatusInvited :
94- return nil , 0 , "" , NewErrAuthUnathorized (nil )
95- case models .UserStatusNotConfirmed :
96- return nil , 0 , "" , NewErrUserNotConfirmed (nil )
97- default :
98- break
99- }
100-
101- // Checks whether the user is currently blocked from new login attempts
102- if lockout , attempt , _ := s .cache .HasAccountLockout (ctx , sourceIP , user .ID ); lockout > 0 {
103- log .
104- WithFields (log.Fields {
105- "lockout" : lockout ,
106- "attempt" : attempt ,
107- "source_ip" : sourceIP ,
108- "user_id" : user .ID ,
109- }).
110- Warn ("attempt to login blocked" )
111-
112- return nil , lockout , "" , NewErrAuthUnathorized (nil )
113- }
114-
115- if ! user .Password .Compare (req .Password ) {
116- lockout , _ , err := s .cache .StoreLoginAttempt (ctx , sourceIP , user .ID )
117- if err != nil {
118- log .WithError (err ).
119- WithField ("source_ip" , sourceIP ).
120- WithField ("user_id" , user .ID ).
121- Warn ("unable to store login attempt" )
122- }
123-
124- return nil , lockout , "" , NewErrAuthUnathorized (nil )
125- }
126-
127- // Reset the attempt and timeout values when succeeds
128- if err := s .cache .ResetLoginAttempts (ctx , sourceIP , user .ID ); err != nil {
129- log .WithError (err ).
130- WithField ("source_ip" , sourceIP ).
131- WithField ("user_id" , user .ID ).
132- Warn ("unable to reset authentication attempts" )
133- }
134-
135- // Users with MFA enabled must authenticate to the cloud instead of community.
136- if user .MFA .Enabled {
137- mfaToken := uuid .Generate ()
138- if err := s .cache .Set (ctx , "mfa-token={" + mfaToken + "}" , user .ID , 30 * time .Minute ); err != nil {
139- log .WithError (err ).
140- WithField ("source_ip" , sourceIP ).
141- WithField ("user_id" , user .ID ).
142- Warn ("unable to store mfa-token" )
143- }
144-
145- return nil , 0 , mfaToken , nil
146- }
147-
148- tenantID := ""
149- role := ""
150- // Populate the tenant and role when the user is associated with a namespace. If the member status is pending, we
151- // ignore the namespace.
152- if ns , _ := s .store .NamespaceGetPreferred (ctx , user .ID ); ns != nil && ns .TenantID != "" {
153- if m , _ := ns .FindMember (user .ID ); m .Status != models .MemberStatusPending {
154- tenantID = ns .TenantID
155- role = m .Role .String ()
156- }
157- }
158-
159- claims := authorizer.UserClaims {
160- ID : user .ID ,
161- Origin : user .Origin .String (),
162- TenantID : tenantID ,
163- Username : user .Username ,
164- MFA : user .MFA .Enabled ,
165- }
166-
167- token , err := jwttoken .EncodeUserClaims (claims , s .privKey )
168- if err != nil {
169- return nil , 0 , "" , NewErrTokenSigned (err )
170- }
171-
172- // Updates last_login and the hash algorithm to bcrypt if still using SHA256
173- changes := & models.UserChanges {LastLogin : clock .Now (), PreferredNamespace : & tenantID }
174- if ! strings .HasPrefix (user .Password .Hash , "$" ) {
175- if neo , _ := models .HashUserPassword (req .Password ); neo .Hash != "" {
176- changes .Password = neo .Hash
177- }
178- }
179-
180- // TODO: evaluate make this update in a go routine.
181- if err := s .store .UserUpdate (ctx , user .ID , changes ); err != nil {
182- return nil , 0 , "" , NewErrUserUpdate (user , err )
183- }
184-
185- if err := s .AuthCacheToken (ctx , tenantID , user .ID , token ); err != nil {
186- log .WithError (err ).
187- WithFields (log.Fields {"id" : user .ID }).
188- Warn ("unable to cache the authentication token" )
189- }
190-
191- res := & models.UserAuthResponse {
192- ID : user .ID ,
193- Origin : user .Origin .String (),
194- AuthMethods : user .Preferences .AuthMethods ,
195- User : user .Username ,
196- Name : user .Name ,
197- Email : user .Email ,
198- RecoveryEmail : user .RecoveryEmail ,
199- MFA : user .MFA .Enabled ,
200- Tenant : tenantID ,
201- Role : role ,
202- Token : token ,
203- MaxNamespaces : user .MaxNamespaces ,
204- }
205-
206- return res , 0 , "" , nil
57+ return nil , 0 , "" , nil
20758}
20859
20960func (s * service ) CreateUserToken (ctx context.Context , req * requests.CreateUserToken ) (* models.UserAuthResponse , error ) {
210- user , _ , err := s .store .UserGetByID (ctx , req .UserID , false )
211- if err != nil {
212- return nil , NewErrUserNotFound (req .UserID , err )
213- }
214-
215- tenantID := ""
216- role := ""
217-
218- switch req .TenantID {
219- case "" :
220- // A user may not have a preferred namespace. In such cases, we create a token without it.
221- namespace , err := s .store .NamespaceGetPreferred (ctx , user .ID )
222- if err != nil {
223- break
224- }
225-
226- member , ok := namespace .FindMember (user .ID )
227- if ! ok {
228- return nil , NewErrNamespaceMemberNotFound (user .ID , nil )
229- }
230-
231- if member .Status != models .MemberStatusPending {
232- tenantID = namespace .TenantID
233- role = member .Role .String ()
234- }
235- default :
236- namespace , err := s .store .NamespaceGet (ctx , req .TenantID )
237- if err != nil {
238- return nil , NewErrNamespaceNotFound (req .TenantID , err )
239- }
240-
241- member , ok := namespace .FindMember (user .ID )
242- if ! ok {
243- return nil , NewErrNamespaceMemberNotFound (user .ID , nil )
244- }
245-
246- if member .Status == models .MemberStatusPending {
247- return nil , NewErrNamespaceMemberNotFound (user .ID , nil )
248- }
249-
250- tenantID = namespace .TenantID
251- role = member .Role .String ()
252-
253- if user .Preferences .PreferredNamespace != namespace .TenantID {
254- _ = s .store .UserUpdate (ctx , user .ID , & models.UserChanges {PreferredNamespace : & tenantID })
255- }
256- }
257-
258- claims := authorizer.UserClaims {
259- ID : user .ID ,
260- Origin : user .Origin .String (),
261- TenantID : tenantID ,
262- Username : user .Username ,
263- MFA : user .MFA .Enabled ,
264- }
265-
266- token , err := jwttoken .EncodeUserClaims (claims , s .privKey )
267- if err != nil {
268- return nil , NewErrTokenSigned (err )
269- }
270-
271- if err := s .AuthCacheToken (ctx , tenantID , user .ID , token ); err != nil {
272- log .WithError (err ).Warn ("unable to cache the user's auth token" )
273- }
274-
275- return & models.UserAuthResponse {
276- ID : user .ID ,
277- Origin : user .Origin .String (),
278- AuthMethods : user .Preferences .AuthMethods ,
279- User : user .Username ,
280- Name : user .Name ,
281- Email : user .Email ,
282- RecoveryEmail : user .RecoveryEmail ,
283- MFA : user .MFA .Enabled ,
284- Tenant : tenantID ,
285- Role : role ,
286- Token : token ,
287- MaxNamespaces : user .MaxNamespaces ,
288- }, nil
61+ return nil , nil
28962}
29063
29164func (s * service ) AuthAPIKey (ctx context.Context , key string ) (* models.APIKey , error ) {
292- apiKey := new (models.APIKey )
293- if err := s .cache .Get (ctx , "api-key={" + key + "}" , apiKey ); err != nil {
294- return nil , err
295- }
296-
297- if apiKey .ID == "" {
298- keySum := sha256 .Sum256 ([]byte (key ))
299- hashedKey := hex .EncodeToString (keySum [:])
300-
301- var err error
302- if apiKey , err = s .store .APIKeyGet (ctx , hashedKey ); err != nil {
303- return nil , NewErrAPIKeyNotFound ("" , err )
304- }
305- }
306-
307- if ! apiKey .IsValid () {
308- return nil , NewErrAPIKeyInvalid (apiKey .Name )
309- }
310-
311- if err := s .cache .Set (ctx , "api-key={" + key + "}" , apiKey , 2 * time .Minute ); err != nil {
312- log .WithError (err ).Info ("Unable to set the api-key in cache" )
313- }
314-
315- return apiKey , nil
65+ return nil , nil
31666}
31767
31868func (s * service ) AuthPublicKey (ctx context.Context , req requests.PublicKeyAuth ) (* models.PublicKeyAuthResponse , error ) {
319- privKey , err := s .store .PrivateKeyGet (ctx , req .Fingerprint )
320- if err != nil {
321- return nil , NewErrPublicKeyNotFound (req .Fingerprint , err )
322- }
323-
324- block , _ := pem .Decode (privKey .Data )
325- if block == nil {
326- return nil , err
327- }
328-
329- key , err := x509 .ParsePKCS1PrivateKey (block .Bytes )
330- if err != nil {
331- return nil , err
332- }
333-
334- digest := sha256 .Sum256 ([]byte (req .Data ))
335- signature , err := rsa .SignPKCS1v15 (rand .Reader , key , crypto .SHA256 , digest [:])
336- if err != nil {
337- return nil , err
338- }
339-
340- return & models.PublicKeyAuthResponse {
341- Signature : base64 .StdEncoding .EncodeToString (signature ),
342- }, nil
69+ return nil , nil
34370}
34471
34572func (s * service ) GetUserRole (ctx context.Context , tenantID , userID string ) (string , error ) {
346- ns , err := s .store .NamespaceGet (ctx , tenantID )
347- if err != nil {
348- return "" , err
349- }
350-
351- member , ok := ns .FindMember (userID )
352- if ! ok {
353- return "" , NewErrNamespaceMemberNotFound (userID , nil )
354- }
355-
356- return member .Role .String (), nil
73+ return "" , nil
35774}
35875
35976func (s * service ) PublicKey () * rsa.PublicKey {
0 commit comments