Skip to content

Commit 6109fad

Browse files
committed
Added RequestAccessTokenViaAuthorizationCodeGrant command
1 parent ec1a84e commit 6109fad

7 files changed

+477
-21
lines changed

authorization_code.go

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package goauth2
2+
3+
import (
4+
"github.com/inklabs/rangedb"
5+
"github.com/inklabs/rangedb/pkg/clock"
6+
)
7+
8+
type authorizationCode struct {
9+
tokenGenerator TokenGenerator
10+
clock clock.Clock
11+
IsLoaded bool
12+
ExpiresAt int64
13+
UserID string
14+
HasBeenPreviouslyUsed bool
15+
PendingEvents []rangedb.Event
16+
}
17+
18+
func newAuthorizationCode(records <-chan *rangedb.Record, generator TokenGenerator, clock clock.Clock) *authorizationCode {
19+
aggregate := &authorizationCode{
20+
tokenGenerator: generator,
21+
clock: clock,
22+
}
23+
24+
for record := range records {
25+
if event, ok := record.Data.(rangedb.Event); ok {
26+
aggregate.apply(event)
27+
}
28+
}
29+
30+
return aggregate
31+
}
32+
33+
func (a *authorizationCode) apply(event rangedb.Event) {
34+
switch e := event.(type) {
35+
36+
case *AuthorizationCodeWasIssuedToUser:
37+
a.IsLoaded = true
38+
a.ExpiresAt = e.ExpiresAt
39+
a.UserID = e.UserID
40+
41+
case *AccessTokenWasIssuedToUserViaAuthorizationCodeGrant:
42+
a.HasBeenPreviouslyUsed = true
43+
44+
case *RefreshTokenWasIssuedToUserViaAuthorizationCodeGrant:
45+
a.HasBeenPreviouslyUsed = true
46+
47+
}
48+
}
49+
50+
func (a *authorizationCode) Handle(command Command) {
51+
switch c := command.(type) {
52+
53+
case RequestAccessTokenViaAuthorizationCodeGrant:
54+
if !a.IsLoaded {
55+
a.emit(RequestAccessTokenViaAuthorizationCodeGrantWasRejectedDueToInvalidAuthorizationCode{
56+
AuthorizationCode: c.AuthorizationCode,
57+
ClientID: c.ClientID,
58+
})
59+
return
60+
}
61+
62+
if a.HasBeenPreviouslyUsed {
63+
a.emit(RequestAccessTokenViaAuthorizationCodeGrantWasRejectedDueToPreviouslyUsedAuthorizationCode{
64+
AuthorizationCode: c.AuthorizationCode,
65+
ClientID: c.ClientID,
66+
})
67+
return
68+
}
69+
70+
if a.isExpired() {
71+
a.emit(RequestAccessTokenViaAuthorizationCodeGrantWasRejectedDueToExpiredAuthorizationCode{
72+
AuthorizationCode: c.AuthorizationCode,
73+
ClientID: c.ClientID,
74+
})
75+
return
76+
}
77+
78+
refreshToken, err := a.tokenGenerator.New()
79+
if err != nil {
80+
// TODO: emit error
81+
return
82+
}
83+
84+
a.emit(
85+
AccessTokenWasIssuedToUserViaAuthorizationCodeGrant{
86+
AuthorizationCode: c.AuthorizationCode,
87+
UserID: a.UserID,
88+
ClientID: c.ClientID,
89+
},
90+
RefreshTokenWasIssuedToUserViaAuthorizationCodeGrant{
91+
AuthorizationCode: c.AuthorizationCode,
92+
UserID: a.UserID,
93+
ClientID: c.ClientID,
94+
RefreshToken: refreshToken,
95+
},
96+
)
97+
98+
}
99+
}
100+
101+
func (a *authorizationCode) emit(events ...rangedb.Event) {
102+
for _, event := range events {
103+
a.apply(event)
104+
}
105+
106+
a.PendingEvents = append(a.PendingEvents, events...)
107+
}
108+
109+
func (a *authorizationCode) GetPendingEvents() []rangedb.Event {
110+
return a.PendingEvents
111+
}
112+
113+
func (a *authorizationCode) isExpired() bool {
114+
return a.clock.Now().Unix() > a.ExpiresAt
115+
}

authorization_code_commands.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package goauth2
2+
3+
//go:generate go run gen/eventgenerator/main.go -package goauth2 -id AuthorizationCode -methodName CommandType -aggregateType authorization-code -inFile authorization_code_commands.go -outFile authorization_code_commands_gen.go
4+
5+
type RequestAccessTokenViaAuthorizationCodeGrant struct {
6+
AuthorizationCode string `json:"authorizationCode"`
7+
ClientID string `json:"clientID"`
8+
ClientSecret string `json:"clientSecret"`
9+
RedirectUri string `json:"redirectUri"`
10+
UserID string `json:"userID"`
11+
}

authorization_code_events.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package goauth2
2+
3+
//go:generate go run gen/eventgenerator/main.go -package goauth2 -id AuthorizationCode -methodName EventType -aggregateType authorization-code -inFile authorization_code_events.go -outFile authorization_code_events_gen.go
4+
5+
// RequestAccessTokenViaAuthorizationCodeGrant events
6+
type AuthorizationCodeWasIssuedToUser struct {
7+
AuthorizationCode string `json:"authorizationCode"`
8+
UserID string `json:"userID"`
9+
ExpiresAt int64 `json:"expiresAt"`
10+
}
11+
type AccessTokenWasIssuedToUserViaAuthorizationCodeGrant struct {
12+
AuthorizationCode string `json:"authorizationCode"`
13+
UserID string `json:"userID"`
14+
ClientID string `json:"clientID"`
15+
}
16+
type RefreshTokenWasIssuedToUserViaAuthorizationCodeGrant struct {
17+
AuthorizationCode string `json:"authorizationCode"`
18+
ClientID string `json:"clientID"`
19+
UserID string `json:"userID"`
20+
RefreshToken string `json:"refreshToken"`
21+
}
22+
type RequestAccessTokenViaAuthorizationCodeGrantWasRejectedDueToInvalidClientApplicationID struct {
23+
AuthorizationCode string `json:"authorizationCode"`
24+
ClientID string `json:"clientID"`
25+
}
26+
type RequestAccessTokenViaAuthorizationCodeGrantWasRejectedDueToInvalidClientApplicationSecret struct {
27+
AuthorizationCode string `json:"authorizationCode"`
28+
ClientID string `json:"clientID"`
29+
}
30+
type RequestAccessTokenViaAuthorizationCodeGrantWasRejectedDueToInvalidClientApplicationRedirectUri struct {
31+
AuthorizationCode string `json:"authorizationCode"`
32+
ClientID string `json:"clientID"`
33+
RedirectUri string `json:"redirectUri"`
34+
}
35+
type RequestAccessTokenViaAuthorizationCodeGrantWasRejectedDueToInvalidAuthorizationCode struct {
36+
AuthorizationCode string `json:"authorizationCode"`
37+
ClientID string `json:"clientID"`
38+
}
39+
type RequestAccessTokenViaAuthorizationCodeGrantWasRejectedDueToExpiredAuthorizationCode struct {
40+
AuthorizationCode string `json:"authorizationCode"`
41+
ClientID string `json:"clientID"`
42+
}
43+
type RequestAccessTokenViaAuthorizationCodeGrantWasRejectedDueToPreviouslyUsedAuthorizationCode struct {
44+
AuthorizationCode string `json:"authorizationCode"`
45+
ClientID string `json:"clientID"`
46+
}

authorization_command_handler.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,34 @@ func (h *authorizationCommandHandler) Handle(command Command) bool {
162162
return false
163163
}
164164

165+
case RequestAccessTokenViaAuthorizationCodeGrant:
166+
clientApplication := h.loadClientApplicationAggregate(c.ClientID)
167+
168+
if !clientApplication.IsOnBoarded {
169+
h.emit(RequestAccessTokenViaAuthorizationCodeGrantWasRejectedDueToInvalidClientApplicationID{
170+
AuthorizationCode: c.AuthorizationCode,
171+
ClientID: c.ClientID,
172+
})
173+
return false
174+
}
175+
176+
if clientApplication.ClientSecret != c.ClientSecret {
177+
h.emit(RequestAccessTokenViaAuthorizationCodeGrantWasRejectedDueToInvalidClientApplicationSecret{
178+
AuthorizationCode: c.AuthorizationCode,
179+
ClientID: c.ClientID,
180+
})
181+
return false
182+
}
183+
184+
if clientApplication.RedirectUri != c.RedirectUri {
185+
h.emit(RequestAccessTokenViaAuthorizationCodeGrantWasRejectedDueToInvalidClientApplicationRedirectUri{
186+
AuthorizationCode: c.AuthorizationCode,
187+
ClientID: c.ClientID,
188+
RedirectUri: c.RedirectUri,
189+
})
190+
return false
191+
}
192+
165193
}
166194

167195
return true

events.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import (
44
"github.com/inklabs/rangedb"
55
)
66

7-
//go:generate go run github.com/inklabs/rangedb/gen/eventbinder -package goauth2 -files client_application_events.go,resource_owner_events.go,refresh_token_events.go
7+
//go:generate go run github.com/inklabs/rangedb/gen/eventbinder -package goauth2 -files client_application_events.go,resource_owner_events.go,refresh_token_events.go,authorization_code_events.go
88

99
//PendingEvents is the interface for retrieving CQRS events that will be saved to the event store.
1010
type PendingEvents interface {

goauth2.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ func (a *App) Dispatch(command Command) []rangedb.Event {
9898
case RequestAuthorizationCodeViaAuthorizationCodeGrant:
9999
events = a.handleWithResourceOwnerAggregate(command)
100100

101+
case RequestAccessTokenViaAuthorizationCodeGrant:
102+
events = a.handleWithAuthorizationCodeAggregate(command)
103+
101104
}
102105

103106
return events
@@ -128,6 +131,16 @@ func (a *App) handleWithRefreshTokenAggregate(command Command) []rangedb.Event {
128131
return a.savePendingEvents(aggregate)
129132
}
130133

134+
func (a *App) handleWithAuthorizationCodeAggregate(command Command) []rangedb.Event {
135+
aggregate := newAuthorizationCode(
136+
a.store.AllEventsByStream(rangedb.GetEventStream(command)),
137+
a.tokenGenerator,
138+
a.clock,
139+
)
140+
aggregate.Handle(command)
141+
return a.savePendingEvents(aggregate)
142+
}
143+
131144
func (a *App) savePendingEvents(events PendingEvents) []rangedb.Event {
132145
pendingEvents := events.GetPendingEvents()
133146
for _, event := range pendingEvents {

0 commit comments

Comments
 (0)