Revert "use AuthRequest code flow to create device tokens"
This reverts commit b885398466
.
This commit is contained in:
parent
75f503ce43
commit
a80ad6df8a
5 changed files with 139 additions and 94 deletions
135
pkg/op/device.go
135
pkg/op/device.go
|
@ -88,7 +88,7 @@ func DeviceAuthorization(w http.ResponseWriter, r *http.Request, o OpenIDProvide
|
|||
VerificationURI: config.UserFormURL,
|
||||
}
|
||||
|
||||
endpoint := o.UserCodeVerificationEndpoint().Absolute(IssuerFromContext(r.Context()))
|
||||
endpoint := o.UserCodeFormEndpoint().Absolute(IssuerFromContext(r.Context()))
|
||||
response.VerificationURIComplete = fmt.Sprintf("%s?user_code=%s", endpoint, userCode)
|
||||
|
||||
httphelper.MarshalJSON(w, response)
|
||||
|
@ -148,6 +148,24 @@ func NewUserCode(charSet []rune, charAmount, dashInterval int) (string, error) {
|
|||
return buf.String(), nil
|
||||
}
|
||||
|
||||
type deviceAccessTokenRequest struct {
|
||||
subject string
|
||||
audience []string
|
||||
scopes []string
|
||||
}
|
||||
|
||||
func (r *deviceAccessTokenRequest) GetSubject() string {
|
||||
return r.subject
|
||||
}
|
||||
|
||||
func (r *deviceAccessTokenRequest) GetAudience() []string {
|
||||
return r.audience
|
||||
}
|
||||
|
||||
func (r *deviceAccessTokenRequest) GetScopes() []string {
|
||||
return r.scopes
|
||||
}
|
||||
|
||||
func DeviceAccessToken(w http.ResponseWriter, r *http.Request, exchanger Exchanger) {
|
||||
if err := deviceAccessToken(w, r, exchanger); err != nil {
|
||||
RequestError(w, r, err)
|
||||
|
@ -161,7 +179,7 @@ func deviceAccessToken(w http.ResponseWriter, r *http.Request, exchanger Exchang
|
|||
defer cancel()
|
||||
r = r.WithContext(ctx)
|
||||
|
||||
clientID, clientAuthenticated, err := ClientIDFromRequest(r, exchanger)
|
||||
clientID, authenticated, err := ClientIDFromRequest(r, exchanger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -170,7 +188,7 @@ func deviceAccessToken(w http.ResponseWriter, r *http.Request, exchanger Exchang
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
state, authReq, err := CheckDeviceAuthorizationState(ctx, clientID, req.DeviceCode, exchanger)
|
||||
state, err := CheckDeviceAuthorizationState(ctx, clientID, req.DeviceCode, exchanger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -179,14 +197,19 @@ func deviceAccessToken(w http.ResponseWriter, r *http.Request, exchanger Exchang
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !clientAuthenticated {
|
||||
if !authenticated {
|
||||
if m := client.AuthMethod(); m != oidc.AuthMethodNone { // Livio: Does this mean "public" client?
|
||||
return oidc.ErrInvalidClient().WithParent(ErrNoClientCredentials).
|
||||
WithDescription(fmt.Sprintf("required client auth method: %s", m))
|
||||
}
|
||||
}
|
||||
|
||||
resp, err := CreateTokenResponse(ctx, authReq, client, exchanger, true, state.AuthCode, "")
|
||||
tokenRequest := &deviceAccessTokenRequest{
|
||||
subject: state.Subject,
|
||||
audience: []string{clientID},
|
||||
scopes: state.Scopes,
|
||||
}
|
||||
resp, err := CreateDeviceTokenResponse(r.Context(), tokenRequest, exchanger, client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -203,88 +226,108 @@ func ParseDeviceAccessTokenRequest(r *http.Request, exchanger Exchanger) (*oidc.
|
|||
return req, nil
|
||||
}
|
||||
|
||||
func CheckDeviceAuthorizationState(ctx context.Context, clientID, deviceCode string, exchanger Exchanger) (*DeviceAuthorizationState, AuthRequest, error) {
|
||||
func CheckDeviceAuthorizationState(ctx context.Context, clientID, deviceCode string, exchanger Exchanger) (*DeviceAuthorizationState, error) {
|
||||
storage, err := assertDeviceStorage(exchanger.Storage())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
state, err := storage.GetDeviceAuthorizatonState(ctx, clientID, deviceCode)
|
||||
if errors.Is(err, context.DeadlineExceeded) {
|
||||
return nil, nil, oidc.ErrSlowDown().WithParent(err)
|
||||
return nil, oidc.ErrSlowDown().WithParent(err)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
if state.Denied {
|
||||
return state, nil, oidc.ErrAccessDenied()
|
||||
return state, oidc.ErrAccessDenied()
|
||||
}
|
||||
if state.AuthCode != "" {
|
||||
return state, nil, nil
|
||||
if state.Completed {
|
||||
return state, nil
|
||||
}
|
||||
if time.Now().After(state.Expires) {
|
||||
return state, nil, oidc.ErrExpiredDeviceCode()
|
||||
return state, oidc.ErrExpiredDeviceCode()
|
||||
}
|
||||
authReq, err := AuthRequestByCode(ctx, exchanger.Storage(), state.AuthCode)
|
||||
return state, authReq, err
|
||||
return state, oidc.ErrAuthorizationPending()
|
||||
}
|
||||
|
||||
func userCodeVerificationHandler(o OpenIDProvider) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
UserCodeVerification(w, r, o)
|
||||
}
|
||||
}
|
||||
func CreateDeviceTokenResponse(ctx context.Context, tokenRequest TokenRequest, creator TokenCreator, client AccessTokenClient) (*oidc.AccessTokenResponse, error) {
|
||||
tokenType := AccessTokenTypeBearer // not sure if this is the correct type?
|
||||
|
||||
type UserCodeVerificationRequest struct {
|
||||
Code string `schema:"code"`
|
||||
UserCode string `schema:"user_code"`
|
||||
RedirectURL string `schema:"redirect_url"`
|
||||
}
|
||||
|
||||
func UserCodeVerification(w http.ResponseWriter, r *http.Request, o OpenIDProvider) {
|
||||
if err := userCodeVerification(w, r, o); err != nil {
|
||||
RequestError(w, r, err)
|
||||
}
|
||||
}
|
||||
|
||||
func userCodeVerification(w http.ResponseWriter, r *http.Request, o OpenIDProvider) (err error) {
|
||||
req, err := ParseUserCodeVerificationRequest(r, o.Decoder())
|
||||
accessToken, refreshToken, validity, err := CreateAccessToken(ctx, tokenRequest, tokenType, creator, client, "")
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &oidc.AccessTokenResponse{
|
||||
AccessToken: accessToken,
|
||||
RefreshToken: refreshToken,
|
||||
TokenType: oidc.BearerToken,
|
||||
ExpiresIn: uint64(validity.Seconds()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func userCodeFormHandler(o OpenIDProvider) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
UserCodeForm(w, r, o)
|
||||
}
|
||||
}
|
||||
|
||||
type UserCodeFormData struct {
|
||||
AccesssToken string `schema:"access_token"`
|
||||
UserCode string `schema:"user_code"`
|
||||
RedirectURL string `schema:"redirect_url"`
|
||||
}
|
||||
|
||||
func UserCodeForm(w http.ResponseWriter, r *http.Request, o OpenIDProvider) {
|
||||
data, err := ParseUserCodeFormData(r, o.Decoder())
|
||||
if err != nil {
|
||||
RequestError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
storage, err := assertDeviceStorage(o.Storage())
|
||||
if err != nil {
|
||||
return err
|
||||
RequestError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx := r.Context()
|
||||
if err := storage.CompleteDeviceAuthorization(ctx, req.Code, req.UserCode); err != nil {
|
||||
return err
|
||||
token, err := VerifyAccessToken(ctx, data.AccesssToken, o.AccessTokenVerifier(ctx))
|
||||
if err != nil {
|
||||
if se := storage.DenyDeviceAuthorization(ctx, data.UserCode); se != nil {
|
||||
err = se
|
||||
}
|
||||
RequestError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
if req.RedirectURL != "" {
|
||||
http.Redirect(w, r, req.RedirectURL, http.StatusSeeOther)
|
||||
if err := storage.CompleteDeviceAuthorization(ctx, data.UserCode, token.GetSubject()); err != nil {
|
||||
RequestError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
if data.RedirectURL != "" {
|
||||
http.Redirect(w, r, data.RedirectURL, http.StatusSeeOther)
|
||||
}
|
||||
|
||||
fmt.Fprintln(w, "Authorization successfull, please return to your device")
|
||||
return nil
|
||||
}
|
||||
|
||||
func ParseUserCodeVerificationRequest(r *http.Request, decoder httphelper.Decoder) (*UserCodeVerificationRequest, error) {
|
||||
func ParseUserCodeFormData(r *http.Request, decoder httphelper.Decoder) (*UserCodeFormData, error) {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
return nil, oidc.ErrInvalidRequest().WithDescription("cannot parse form").WithParent(err)
|
||||
}
|
||||
|
||||
req := new(UserCodeVerificationRequest)
|
||||
req := new(UserCodeFormData)
|
||||
if err := decoder.Decode(req, r.Form); err != nil {
|
||||
return nil, oidc.ErrInvalidRequest().WithDescription("cannot parse user code form").WithParent(err)
|
||||
}
|
||||
if req.Code == "" {
|
||||
return nil, oidc.ErrInvalidRequest().WithDescription("\"code\" missing in form")
|
||||
if req.AccesssToken == "" {
|
||||
return nil, oidc.ErrInvalidRequest().WithDescription("access_token missing in form")
|
||||
}
|
||||
if req.UserCode == "" {
|
||||
return nil, oidc.ErrInvalidRequest().WithDescription("\"user_code\" missing in form")
|
||||
return nil, oidc.ErrInvalidRequest().WithDescription("user_code missing in form")
|
||||
}
|
||||
|
||||
return req, nil
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue