implement RFC 8628: Device authorization grant
This commit is contained in:
parent
03f71a67c2
commit
2342f208ef
29 changed files with 1968 additions and 97 deletions
|
@ -44,6 +44,8 @@ type Storage struct {
|
|||
services map[string]Service
|
||||
refreshTokens map[string]*RefreshToken
|
||||
signingKey signingKey
|
||||
deviceCodes map[string]deviceAuthorizationEntry
|
||||
userCodes map[string]string
|
||||
}
|
||||
|
||||
type signingKey struct {
|
||||
|
@ -105,6 +107,8 @@ func NewStorage(userStore UserStore) *Storage {
|
|||
algorithm: jose.RS256,
|
||||
key: key,
|
||||
},
|
||||
deviceCodes: make(map[string]deviceAuthorizationEntry),
|
||||
userCodes: make(map[string]string),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -135,6 +139,17 @@ func (s *Storage) CheckUsernamePassword(username, password, id string) error {
|
|||
return fmt.Errorf("username or password wrong")
|
||||
}
|
||||
|
||||
func (s *Storage) CheckUsernamePasswordSimple(username, password string) error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
user := s.userStore.GetUserByUsername(username)
|
||||
if user != nil && user.Password == password {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("username or password wrong")
|
||||
}
|
||||
|
||||
// CreateAuthRequest implements the op.Storage interface
|
||||
// it will be called after parsing and validation of the authentication request
|
||||
func (s *Storage) CreateAuthRequest(ctx context.Context, authReq *oidc.AuthRequest, userID string) (op.AuthRequest, error) {
|
||||
|
@ -735,3 +750,85 @@ func appendClaim(claims map[string]interface{}, claim string, value interface{})
|
|||
claims[claim] = value
|
||||
return claims
|
||||
}
|
||||
|
||||
type deviceAuthorizationEntry struct {
|
||||
deviceCode string
|
||||
userCode string
|
||||
state *op.DeviceAuthorizationState
|
||||
}
|
||||
|
||||
func (s *Storage) StoreDeviceAuthorization(ctx context.Context, clientID, deviceCode, userCode string, expires time.Time, scopes []string) error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
if _, ok := s.clients[clientID]; !ok {
|
||||
return errors.New("client not found")
|
||||
}
|
||||
|
||||
if _, ok := s.userCodes[userCode]; ok {
|
||||
return op.ErrDuplicateUserCode
|
||||
}
|
||||
|
||||
s.deviceCodes[deviceCode] = deviceAuthorizationEntry{
|
||||
deviceCode: deviceCode,
|
||||
userCode: userCode,
|
||||
state: &op.DeviceAuthorizationState{
|
||||
ClientID: clientID,
|
||||
Scopes: scopes,
|
||||
Expires: expires,
|
||||
},
|
||||
}
|
||||
|
||||
s.userCodes[userCode] = deviceCode
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Storage) GetDeviceAuthorizatonState(ctx context.Context, clientID, deviceCode string) (*op.DeviceAuthorizationState, error) {
|
||||
if ctx.Err() != nil {
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
entry, ok := s.deviceCodes[deviceCode]
|
||||
if !ok || entry.state.ClientID != clientID {
|
||||
return nil, errors.New("device code not found for client") // is there a standard not found error in the framework?
|
||||
}
|
||||
|
||||
return entry.state, nil
|
||||
}
|
||||
|
||||
func (s *Storage) GetDeviceAuthorizationByUserCode(ctx context.Context, userCode string) (*op.DeviceAuthorizationState, error) {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
entry, ok := s.deviceCodes[s.userCodes[userCode]]
|
||||
if !ok {
|
||||
return nil, errors.New("user code not found")
|
||||
}
|
||||
|
||||
return entry.state, nil
|
||||
}
|
||||
|
||||
func (s *Storage) CompleteDeviceAuthorization(ctx context.Context, userCode, subject string) error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
entry, ok := s.deviceCodes[s.userCodes[userCode]]
|
||||
if !ok {
|
||||
return errors.New("user code not found")
|
||||
}
|
||||
|
||||
entry.state.Subject = subject
|
||||
entry.state.Done = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Storage) DenyDeviceAuthorization(ctx context.Context, userCode string) error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
s.deviceCodes[s.userCodes[userCode]].state.Denied = true
|
||||
return nil
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue