github.com/resonatecoop/id@v1.1.0-43/oauth/client.go (about) 1 package oauth 2 3 import ( 4 "context" 5 "errors" 6 "strings" 7 8 "github.com/resonatecoop/id/util" 9 "github.com/resonatecoop/id/util/password" 10 "github.com/resonatecoop/user-api/model" 11 "github.com/uptrace/bun" 12 ) 13 14 var ( 15 // ErrClientNotFound ... 16 ErrClientNotFound = errors.New("Client not found") 17 // ErrInvalidClientSecret ... 18 ErrInvalidClientSecret = errors.New("Invalid client secret") 19 // ErrClientIDTaken ... 20 ErrClientIDTaken = errors.New("Client ID taken") 21 ) 22 23 // ClientExists returns true if client exists 24 func (s *Service) ClientExists(clientID string) bool { 25 _, err := s.FindClientByClientID(clientID) 26 return err == nil 27 } 28 29 // FindClientByClientID looks up a client by client ID 30 func (s *Service) FindClientByClientID(clientID string) (*model.Client, error) { 31 // Client IDs are case insensitive 32 ctx := context.Background() 33 client := new(model.Client) 34 35 err := s.db.NewSelect(). 36 Model(client). 37 Where("key = LOWER(?)", clientID). 38 Limit(1). 39 Scan(ctx) 40 41 // Not Found! 42 if err != nil { 43 return nil, ErrClientNotFound 44 } 45 46 return client, nil 47 } 48 49 // FindClientByRedirectURI looks up a client by redirect URI 50 func (s *Service) FindClientByApplicationURL(applicationURL string) (*model.Client, error) { 51 ctx := context.Background() 52 client := new(model.Client) 53 54 err := s.db.NewSelect(). 55 Model(client). 56 Where("application_url = ? AND application_hostname IN (?)", applicationURL, bun.In(s.cnf.Origins)). 57 Limit(1). 58 Scan(ctx) 59 60 // Not Found! 61 if err != nil { 62 return nil, ErrClientNotFound 63 } 64 65 return client, nil 66 } 67 68 // CreateClient saves a new client to database 69 func (s *Service) CreateClient(clientID, secret, redirectURI, applicationName, applicationHostname, applicationURL string) (*model.Client, error) { 70 return s.createClientCommon(s.db, clientID, secret, redirectURI, applicationName, applicationHostname, applicationURL) 71 } 72 73 // CreateClientTx saves a new client to database using injected db object 74 func (s *Service) CreateClientTx(tx *bun.DB, clientID, secret, redirectURI, applicationName, applicationHostname, applicationURL string) (*model.Client, error) { 75 return s.createClientCommon(tx, clientID, secret, redirectURI, applicationName, applicationHostname, applicationURL) 76 } 77 78 // AuthClient authenticates client 79 func (s *Service) AuthClient(clientID, secret string) (*model.Client, error) { 80 // Fetch the client 81 client, err := s.FindClientByClientID(clientID) 82 if err != nil { 83 return nil, ErrClientNotFound 84 } 85 86 // Verify the secret 87 if password.VerifyPassword(client.Secret, secret) != nil { 88 return nil, ErrInvalidClientSecret 89 } 90 91 return client, nil 92 } 93 94 func (s *Service) createClientCommon(db *bun.DB, clientID, secret, redirectURI, applicationName, applicationHostname, applicationURL string) (*model.Client, error) { 95 ctx := context.Background() 96 // Check client ID 97 if s.ClientExists(clientID) { 98 return nil, ErrClientIDTaken 99 } 100 101 // Hash password 102 secretHash, err := password.HashPassword(secret) 103 if err != nil { 104 return nil, err 105 } 106 107 client := &model.Client{ 108 Key: strings.ToLower(clientID), 109 Secret: string(secretHash), 110 RedirectURI: util.StringOrNull(redirectURI), 111 ApplicationName: util.StringOrNull(applicationName), 112 ApplicationHostname: util.StringOrNull(strings.ToLower(applicationHostname)), 113 ApplicationURL: util.StringOrNull(strings.ToLower(applicationURL)), 114 } 115 116 _, err = s.db.NewInsert().Model(client).Exec(ctx) 117 if err != nil { 118 return nil, err 119 } 120 121 return client, nil 122 }