@@ -17,17 +17,22 @@ package authn
17
17
import (
18
18
"context"
19
19
"fmt"
20
+ "net/http"
21
+ "strings"
22
+
20
23
"github.com/greenpau/go-authcrunch/pkg/requests"
24
+ "github.com/greenpau/go-authcrunch/pkg/sso"
21
25
"github.com/greenpau/go-authcrunch/pkg/user"
22
26
"go.uber.org/zap"
23
- "net/http"
24
- "strings"
25
27
)
26
28
27
- func (p * Portal ) handleHTTPAppsSingleSignOn (ctx context.Context , w http.ResponseWriter , r * http.Request , rr * requests.Request , parsedUser * user.User ) error {
28
- var assumedRole , authorizedRole bool
29
- var accountID , roleName string
29
+ type assumeRoleEntry struct {
30
+ Name string
31
+ AccountID string
32
+ ProviderName string
33
+ }
30
34
35
+ func (p * Portal ) handleHTTPAppsSingleSignOn (ctx context.Context , w http.ResponseWriter , r * http.Request , rr * requests.Request , parsedUser * user.User ) error {
31
36
p .disableClientCache (w )
32
37
p .injectRedirectURL (ctx , w , r , rr )
33
38
@@ -54,55 +59,69 @@ func (p *Portal) handleHTTPAppsSingleSignOn(ctx context.Context, w http.Response
54
59
return p .handleHTTPRedirect (ctx , w , r , rr , "/login" )
55
60
}
56
61
57
- resp := p .ui .GetArgs ()
58
- resp .PageTitle = "AWS SSO"
59
- resp .BaseURL (rr .Upstream .BasePath )
60
-
61
- if strings .Contains (r .URL .Path , "/apps/sso" ) && strings .Contains (r .URL .Path , "metadata.xml" ) {
62
- // TODO(greenpau): add metadata for realm.
62
+ // Parse SSO provider name from URL.
63
+ req , err := sso .ParseRequestURL (r )
64
+ if err != nil {
65
+ return p .handleHTTPRenderError (ctx , w , r , rr , err )
63
66
}
64
67
65
- if strings .Contains (r .URL .Path , "/apps/sso/assume" ) {
66
- accountRole , err := getEndpoint (r .URL .Path , "/apps/sso/assume/" )
67
- if err != nil {
68
- p .logger .Warn (
69
- "SSO request failed" ,
70
- zap .String ("session_id" , rr .Upstream .SessionID ),
71
- zap .String ("request_id" , rr .ID ),
72
- zap .String ("error" , "malformed SSO request" ),
73
- )
74
- } else {
75
- assumedRole = true
76
- arr := strings .SplitN (accountRole , "/" , 2 )
77
- if len (arr ) != 2 {
78
- return p .handleHTTPRenderError (ctx , w , r , rr , fmt .Errorf ("Malformed SSO request" ))
79
- }
80
- accountID = arr [0 ]
81
- roleName = arr [1 ]
82
- }
68
+ // Check whether the requested SSO provider exists.
69
+ provider , err := p .fetchSingleSignOnProvider (req .ProviderName )
70
+ if err != nil {
71
+ return p .handleHTTPRenderError (ctx , w , r , rr , err )
83
72
}
84
73
85
- type roleEntry struct {
86
- Name string
87
- AccountID string
74
+ roles := fetchSingleSignOnRoles (provider .GetName (), usr )
75
+
76
+ switch req .Kind {
77
+ case sso .MetadataRequest :
78
+ return p .handleHTTPAppsSingleSignOnMetadata (ctx , w , r , rr , provider , roles )
79
+ case sso .AssumeRoleRequest :
80
+ return p .handleHTTPAppsSingleSignOnAssumeRole (ctx , w , r , rr , provider , roles , usr )
81
+ case sso .MenuRequest :
82
+ return p .handleHTTPAppsSingleSignOnMenu (ctx , w , r , rr , provider , roles , usr )
88
83
}
84
+ return p .handleHTTPAppsSingleSignOnMenu (ctx , w , r , rr , provider , roles , usr )
85
+ }
89
86
90
- roles := []* roleEntry {}
91
- for _ , entry := range usr .Claims .Roles {
92
- arr := strings .Split (entry , "/" )
93
- if len (arr ) != 3 {
94
- continue
95
- }
96
- if arr [0 ] != "aws" {
97
- continue
98
- }
99
- role := & roleEntry {
100
- Name : arr [2 ],
101
- AccountID : arr [1 ],
87
+ // handleHTTPAppsSingleSignOnMetadata renders metadata.xml content. It is only available to admin users.
88
+ func (p * Portal ) handleHTTPAppsSingleSignOnMetadata (ctx context.Context , w http.ResponseWriter , r * http.Request , rr * requests.Request ,
89
+ provider sso.SingleSignOnProvider , roles []* assumeRoleEntry ) error {
90
+ // body := []byte("METADATA")
91
+ w .Header ().Set ("Content-Type" , "text/html" )
92
+ w .WriteHeader (http .StatusOK )
93
+ // w.Write(body)
94
+ w .Write (provider .GetMetadata ())
95
+ return nil
96
+ }
97
+
98
+ func (p * Portal ) handleHTTPAppsSingleSignOnAssumeRole (ctx context.Context , w http.ResponseWriter , r * http.Request , rr * requests.Request ,
99
+ provider sso.SingleSignOnProvider , roles []* assumeRoleEntry , usr * user.User ) error {
100
+
101
+ /*
102
+ if strings.Contains(r.URL.Path, "/apps/sso/assume") {
103
+ accountRole, err := getEndpoint(r.URL.Path, "/apps/sso/assume/")
104
+ if err != nil {
105
+ p.logger.Warn(
106
+ "SSO request failed",
107
+ zap.String("session_id", rr.Upstream.SessionID),
108
+ zap.String("request_id", rr.ID),
109
+ zap.String("error", "malformed SSO request"),
110
+ )
111
+ } else {
112
+ assumedRole = true
113
+ arr := strings.SplitN(accountRole, "/", 2)
114
+ if len(arr) != 2 {
115
+ return p.handleHTTPRenderError(ctx, w, r, rr, fmt.Errorf("Malformed SSO request"))
116
+ }
117
+ accountID = arr[0]
118
+ roleName = arr[1]
119
+ }
102
120
}
103
- roles = append ( roles , role )
121
+ */
104
122
105
- if assumedRole {
123
+ /*
124
+ if assumedRole {
106
125
if (role.Name == roleName) && (role.AccountID == accountID) {
107
126
authorizedRole = true
108
127
p.logger.Debug(
@@ -114,22 +133,39 @@ func (p *Portal) handleHTTPAppsSingleSignOn(ctx context.Context, w http.Response
114
133
)
115
134
}
116
135
}
117
- }
136
+ */
118
137
119
- if assumedRole {
120
- if ! authorizedRole {
121
- p .logger .Debug (
122
- "Unauthorized SSO assume role request" ,
123
- zap .String ("session_id" , rr .Upstream .SessionID ),
124
- zap .String ("request_id" , rr .ID ),
125
- zap .String ("role_name" , roleName ),
126
- zap .String ("account_id" , accountID ),
127
- )
128
- return p .handleHTTPRenderError (ctx , w , r , rr , fmt .Errorf ("Unauthorized SSO assume role request" ))
138
+ /*
139
+ if assumedRole {
140
+ if !authorizedRole {
141
+ p.logger.Debug(
142
+ "Unauthorized SSO assume role request",
143
+ zap.String("session_id", rr.Upstream.SessionID),
144
+ zap.String("request_id", rr.ID),
145
+ zap.String("role_name", roleName),
146
+ zap.String("account_id", accountID),
147
+ )
148
+ return p.handleHTTPRenderError(ctx, w, r, rr, fmt.Errorf("Unauthorized SSO assume role request"))
149
+ }
150
+ p.logger.Debug("Redirecting to SAML endpoint")
129
151
}
130
- p .logger .Debug ("Redirecting to SAML endpoint" )
131
- }
132
152
153
+ */
154
+
155
+ body := []byte ("ASSUME ROLE" )
156
+ w .Header ().Set ("Content-Type" , "text/html" )
157
+ w .WriteHeader (http .StatusOK )
158
+ w .Write (body )
159
+ return nil
160
+ }
161
+
162
+ // handleHTTPAppsSingleSignOnMenu renders SSO provider role selection page.
163
+ func (p * Portal ) handleHTTPAppsSingleSignOnMenu (ctx context.Context , w http.ResponseWriter , r * http.Request , rr * requests.Request ,
164
+ provider sso.SingleSignOnProvider , roles []* assumeRoleEntry , usr * user.User ) error {
165
+
166
+ resp := p .ui .GetArgs ()
167
+ resp .PageTitle = "AWS SSO"
168
+ resp .BaseURL (rr .Upstream .BasePath )
133
169
resp .Data ["role_count" ] = len (roles )
134
170
resp .Data ["roles" ] = roles
135
171
@@ -139,3 +175,36 @@ func (p *Portal) handleHTTPAppsSingleSignOn(ctx context.Context, w http.Response
139
175
}
140
176
return p .handleHTTPRenderHTML (ctx , w , http .StatusOK , content .Bytes ())
141
177
}
178
+
179
+ func (p * Portal ) fetchSingleSignOnProvider (providerName string ) (sso.SingleSignOnProvider , error ) {
180
+ for _ , provider := range p .ssoProviders {
181
+ if provider .GetName () == providerName {
182
+ return provider , nil
183
+ }
184
+ }
185
+ return nil , fmt .Errorf ("provider name not found" )
186
+ }
187
+
188
+ func (p * Portal ) parseSingleSignOnProviderName () (string , string , error ) {
189
+ return "aws" , "metadata" , nil
190
+ }
191
+
192
+ func fetchSingleSignOnRoles (providerName string , usr * user.User ) []* assumeRoleEntry {
193
+ roles := []* assumeRoleEntry {}
194
+ for _ , entry := range usr .Claims .Roles {
195
+ arr := strings .Split (entry , "/" )
196
+ if len (arr ) != 3 {
197
+ continue
198
+ }
199
+ if arr [0 ] != "aws" {
200
+ continue
201
+ }
202
+ role := & assumeRoleEntry {
203
+ Name : arr [2 ],
204
+ AccountID : arr [1 ],
205
+ ProviderName : providerName ,
206
+ }
207
+ roles = append (roles , role )
208
+ }
209
+ return roles
210
+ }
0 commit comments