...
1
21
22 package oauth2
23
24 import (
25 "context"
26 "time"
27
28 "github.com/ory/x/errorsx"
29
30 "github.com/pkg/errors"
31
32 "github.com/ory/fosite"
33 )
34
35
36
37
38 type ResourceOwnerPasswordCredentialsGrantHandler struct {
39
40 ResourceOwnerPasswordCredentialsGrantStorage ResourceOwnerPasswordCredentialsGrantStorage
41
42 RefreshTokenStrategy RefreshTokenStrategy
43 ScopeStrategy fosite.ScopeStrategy
44 AudienceMatchingStrategy fosite.AudienceMatchingStrategy
45 RefreshTokenScopes []string
46
47 *HandleHelper
48 }
49
50
51 func (c *ResourceOwnerPasswordCredentialsGrantHandler) HandleTokenEndpointRequest(ctx context.Context, request fosite.AccessRequester) error {
52 if !c.CanHandleTokenEndpointRequest(request) {
53 return errorsx.WithStack(fosite.ErrUnknownRequest)
54 }
55
56 if !request.GetClient().GetGrantTypes().Has("password") {
57 return errorsx.WithStack(fosite.ErrUnauthorizedClient.WithHint("The client is not allowed to use authorization grant 'password'."))
58 }
59
60 client := request.GetClient()
61 for _, scope := range request.GetRequestedScopes() {
62 if !c.ScopeStrategy(client.GetScopes(), scope) {
63 return errorsx.WithStack(fosite.ErrInvalidScope.WithHintf("The OAuth 2.0 Client is not allowed to request scope '%s'.", scope))
64 }
65 }
66
67 if err := c.AudienceMatchingStrategy(client.GetAudience(), request.GetRequestedAudience()); err != nil {
68 return err
69 }
70
71 username := request.GetRequestForm().Get("username")
72 password := request.GetRequestForm().Get("password")
73 if username == "" || password == "" {
74 return errorsx.WithStack(fosite.ErrInvalidRequest.WithHint("Username or password are missing from the POST body."))
75 } else if err := c.ResourceOwnerPasswordCredentialsGrantStorage.Authenticate(ctx, username, password); errors.Is(err, fosite.ErrNotFound) {
76 return errorsx.WithStack(fosite.ErrInvalidGrant.WithHint("Unable to authenticate the provided username and password credentials.").WithWrap(err).WithDebug(err.Error()))
77 } else if err != nil {
78 return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error()))
79 }
80
81
82 delete(request.GetRequestForm(), "password")
83
84 request.GetSession().SetExpiresAt(fosite.AccessToken, time.Now().UTC().Add(c.AccessTokenLifespan).Round(time.Second))
85 if c.RefreshTokenLifespan > -1 {
86 request.GetSession().SetExpiresAt(fosite.RefreshToken, time.Now().UTC().Add(c.RefreshTokenLifespan).Round(time.Second))
87 }
88
89 return nil
90 }
91
92
93 func (c *ResourceOwnerPasswordCredentialsGrantHandler) PopulateTokenEndpointResponse(ctx context.Context, requester fosite.AccessRequester, responder fosite.AccessResponder) error {
94 if !c.CanHandleTokenEndpointRequest(requester) {
95 return errorsx.WithStack(fosite.ErrUnknownRequest)
96 }
97
98 var refresh, refreshSignature string
99 if len(c.RefreshTokenScopes) == 0 || requester.GetGrantedScopes().HasOneOf(c.RefreshTokenScopes...) {
100 var err error
101 refresh, refreshSignature, err = c.RefreshTokenStrategy.GenerateRefreshToken(ctx, requester)
102 if err != nil {
103 return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error()))
104 } else if err := c.ResourceOwnerPasswordCredentialsGrantStorage.CreateRefreshTokenSession(ctx, refreshSignature, requester.Sanitize([]string{})); err != nil {
105 return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error()))
106 }
107 }
108
109 if err := c.IssueAccessToken(ctx, requester, responder); err != nil {
110 return err
111 }
112
113 if refresh != "" {
114 responder.SetExtra("refresh_token", refresh)
115 }
116
117 return nil
118 }
119
120 func (c *ResourceOwnerPasswordCredentialsGrantHandler) CanSkipClientAuth(requester fosite.AccessRequester) bool {
121 return false
122 }
123
124 func (c *ResourceOwnerPasswordCredentialsGrantHandler) CanHandleTokenEndpointRequest(requester fosite.AccessRequester) bool {
125
126
127 return requester.GetGrantTypes().ExactOne("password")
128 }
129
View as plain text