2020-04-01 18:18:57 -07:00
|
|
|
// This file is part of MinIO Console Server
|
2021-01-19 17:04:13 -06:00
|
|
|
// Copyright (c) 2021 MinIO, Inc.
|
2020-04-01 18:18:57 -07:00
|
|
|
//
|
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
|
// it under the terms of the GNU Affero General Public License as published by
|
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
// (at your option) any later version.
|
|
|
|
|
//
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
// GNU Affero General Public License for more details.
|
|
|
|
|
//
|
|
|
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
|
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
2023-12-26 15:07:30 -06:00
|
|
|
package api
|
2020-04-01 18:18:57 -07:00
|
|
|
|
|
|
|
|
import (
|
2020-05-01 08:38:52 -07:00
|
|
|
"context"
|
2022-10-20 20:08:54 -05:00
|
|
|
"encoding/base64"
|
|
|
|
|
"encoding/json"
|
2023-03-07 16:10:21 -06:00
|
|
|
"fmt"
|
2020-11-13 16:26:03 -08:00
|
|
|
"net/http"
|
2023-03-07 16:10:21 -06:00
|
|
|
"strings"
|
2020-04-01 18:18:57 -07:00
|
|
|
|
2023-05-22 11:20:45 -06:00
|
|
|
"github.com/go-openapi/errors"
|
|
|
|
|
|
2020-11-13 16:26:03 -08:00
|
|
|
"github.com/go-openapi/runtime"
|
2020-04-01 18:18:57 -07:00
|
|
|
"github.com/go-openapi/runtime/middleware"
|
2023-12-26 15:07:30 -06:00
|
|
|
"github.com/minio/console/api/operations"
|
|
|
|
|
authApi "github.com/minio/console/api/operations/auth"
|
2020-07-26 00:34:17 -07:00
|
|
|
"github.com/minio/console/models"
|
|
|
|
|
"github.com/minio/console/pkg/auth"
|
|
|
|
|
"github.com/minio/console/pkg/auth/idp/oauth2"
|
2023-06-21 10:51:12 -07:00
|
|
|
"github.com/minio/madmin-go/v3"
|
2022-10-20 20:08:54 -05:00
|
|
|
"github.com/minio/minio-go/v7/pkg/credentials"
|
2024-05-24 10:44:55 -07:00
|
|
|
"github.com/minio/pkg/v3/env"
|
2020-04-01 18:18:57 -07:00
|
|
|
)
|
|
|
|
|
|
2020-07-26 00:34:17 -07:00
|
|
|
func registerLoginHandlers(api *operations.ConsoleAPI) {
|
2021-11-11 14:46:14 -08:00
|
|
|
// GET login strategy
|
2022-04-27 11:45:04 -07:00
|
|
|
api.AuthLoginDetailHandler = authApi.LoginDetailHandlerFunc(func(params authApi.LoginDetailParams) middleware.Responder {
|
2022-10-20 20:08:54 -05:00
|
|
|
loginDetails, err := getLoginDetailsResponse(params, GlobalMinIOConfig.OpenIDProviders)
|
2020-05-01 08:38:52 -07:00
|
|
|
if err != nil {
|
2023-08-16 14:18:08 -07:00
|
|
|
return authApi.NewLoginDetailDefault(err.Code).WithPayload(err.APIError)
|
2020-05-01 08:38:52 -07:00
|
|
|
}
|
2022-04-27 11:45:04 -07:00
|
|
|
return authApi.NewLoginDetailOK().WithPayload(loginDetails)
|
2020-04-01 18:18:57 -07:00
|
|
|
})
|
2021-11-11 14:46:14 -08:00
|
|
|
// POST login using user credentials
|
2022-04-27 11:45:04 -07:00
|
|
|
api.AuthLoginHandler = authApi.LoginHandlerFunc(func(params authApi.LoginParams) middleware.Responder {
|
2022-04-28 12:55:06 -07:00
|
|
|
loginResponse, err := getLoginResponse(params)
|
2020-04-01 18:18:57 -07:00
|
|
|
if err != nil {
|
2023-08-16 14:18:08 -07:00
|
|
|
return authApi.NewLoginDefault(err.Code).WithPayload(err.APIError)
|
2020-04-01 18:18:57 -07:00
|
|
|
}
|
2020-11-13 16:26:03 -08:00
|
|
|
// Custom response writer to set the session cookies
|
|
|
|
|
return middleware.ResponderFunc(func(w http.ResponseWriter, p runtime.Producer) {
|
2021-10-12 21:25:02 -07:00
|
|
|
cookie := NewSessionCookieForConsole(loginResponse.SessionID)
|
|
|
|
|
http.SetCookie(w, &cookie)
|
2022-04-27 11:45:04 -07:00
|
|
|
authApi.NewLoginNoContent().WriteResponse(w, p)
|
2020-11-13 16:26:03 -08:00
|
|
|
})
|
2020-04-01 18:18:57 -07:00
|
|
|
})
|
2021-11-11 14:46:14 -08:00
|
|
|
// POST login using external IDP
|
2022-04-27 11:45:04 -07:00
|
|
|
api.AuthLoginOauth2AuthHandler = authApi.LoginOauth2AuthHandlerFunc(func(params authApi.LoginOauth2AuthParams) middleware.Responder {
|
2022-10-20 20:08:54 -05:00
|
|
|
loginResponse, err := getLoginOauth2AuthResponse(params, GlobalMinIOConfig.OpenIDProviders)
|
2020-05-01 08:38:52 -07:00
|
|
|
if err != nil {
|
2023-08-16 14:18:08 -07:00
|
|
|
return authApi.NewLoginOauth2AuthDefault(err.Code).WithPayload(err.APIError)
|
2020-05-01 08:38:52 -07:00
|
|
|
}
|
2020-11-13 16:26:03 -08:00
|
|
|
// Custom response writer to set the session cookies
|
|
|
|
|
return middleware.ResponderFunc(func(w http.ResponseWriter, p runtime.Producer) {
|
2021-10-12 21:25:02 -07:00
|
|
|
cookie := NewSessionCookieForConsole(loginResponse.SessionID)
|
|
|
|
|
http.SetCookie(w, &cookie)
|
2022-12-05 18:14:41 -06:00
|
|
|
http.SetCookie(w, &http.Cookie{
|
|
|
|
|
Path: "/",
|
|
|
|
|
Name: "idp-refresh-token",
|
|
|
|
|
Value: loginResponse.IDPRefreshToken,
|
|
|
|
|
HttpOnly: true,
|
|
|
|
|
Secure: len(GlobalPublicCerts) > 0,
|
|
|
|
|
SameSite: http.SameSiteLaxMode,
|
|
|
|
|
})
|
2022-04-27 11:45:04 -07:00
|
|
|
authApi.NewLoginOauth2AuthNoContent().WriteResponse(w, p)
|
2020-11-13 16:26:03 -08:00
|
|
|
})
|
MCS service account authentication with Mkube (#166)
`MCS` will authenticate against `Mkube`using bearer tokens via HTTP
`Authorization` header. The user will provide this token once
in the login form, MCS will validate it against Mkube (list tenants) and
if valid will generate and return a new MCS sessions
with encrypted claims (the user Service account token will be inside the
JWT in the data field)
Kubernetes
The provided `JWT token` corresponds to the `Kubernetes service account`
that `Mkube` will use to run tasks on behalf of the
user, ie: list, create, edit, delete tenants, storage class, etc.
Development
If you are running mcs in your local environment and wish to make
request to `Mkube` you can set `MCS_M3_HOSTNAME`, if
the environment variable is not present by default `MCS` will use
`"http://m3:8787"`, additionally you will need to set the
`MCS_MKUBE_ADMIN_ONLY=on` variable to make MCS display the Mkube UI
Extract the Service account token and use it with MCS
For local development you can use the jwt associated to the `m3-sa`
service account, you can get the token running
the following command in your terminal:
```
kubectl get secret $(kubectl get serviceaccount m3-sa -o
jsonpath="{.secrets[0].name}") -o jsonpath="{.data.token}" | base64
--decode
```
Then run the mcs server
```
MCS_M3_HOSTNAME=http://localhost:8787 MCS_MKUBE_ADMIN_ONLY=on ./mcs
server
```
Self-signed certificates and Custom certificate authority for Mkube
If Mkube uses TLS with a self-signed certificate, or a certificate
issued by a custom certificate authority you can add those
certificates usinng the `MCS_M3_SERVER_TLS_CA_CERTIFICATE` env variable
````
MCS_M3_SERVER_TLS_CA_CERTIFICATE=cert1.pem,cert2.pem,cert3.pem ./mcs
server
````
2020-06-23 11:37:46 -07:00
|
|
|
})
|
2020-04-01 18:18:57 -07:00
|
|
|
}
|
|
|
|
|
|
2021-07-19 11:48:50 -07:00
|
|
|
// login performs a check of ConsoleCredentials against MinIO, generates some claims and returns the jwt
|
ACL for mcs (#123)
This PR sets the initial version of the ACL for mcs, the idea behind
this is to start using the principle of least privileges when assigning
policies to users when creating users through mcs, currently mcsAdmin policy uses admin:*
and s3:* and by default a user with that policy will have access to everything, if want to limit
that we can create a policy with least privileges.
We need to start validating explicitly if users has acccess to an
specific endpoint based on IAM policy actions.
In this first version every endpoint (you can see it as a page to),
defines a set of well defined admin/s3 actions to work properly, ie:
```
// corresponds to /groups endpoint used by the groups page
var groupsActionSet = iampolicy.NewActionSet(
iampolicy.ListGroupsAdminAction,
iampolicy.AddUserToGroupAdminAction,
//iampolicy.GetGroupAdminAction,
iampolicy.EnableGroupAdminAction,
iampolicy.DisableGroupAdminAction,
)
// corresponds to /policies endpoint used by the policies page
var iamPoliciesActionSet = iampolicy.NewActionSet(
iampolicy.GetPolicyAdminAction,
iampolicy.DeletePolicyAdminAction,
iampolicy.CreatePolicyAdminAction,
iampolicy.AttachPolicyAdminAction,
iampolicy.ListUserPoliciesAdminAction,
)
```
With that said, for this initial version, now the sessions endpoint will
return a list of authorized pages to be render on the UI, on subsequent
prs we will add this verification of authorization via a server
middleware.
2020-05-18 18:03:06 -07:00
|
|
|
// for subsequent authentication
|
2022-02-21 21:42:18 -08:00
|
|
|
func login(credentials ConsoleCredentialsI, sessionFeatures *auth.SessionFeatures) (*string, error) {
|
2020-07-26 00:34:17 -07:00
|
|
|
// try to obtain consoleCredentials,
|
2020-04-22 23:43:17 -07:00
|
|
|
tokens, err := credentials.Get()
|
|
|
|
|
if err != nil {
|
2020-09-04 20:32:57 -07:00
|
|
|
return nil, err
|
2020-04-01 18:18:57 -07:00
|
|
|
}
|
2023-05-22 11:20:45 -06:00
|
|
|
|
2020-07-26 00:34:17 -07:00
|
|
|
// if we made it here, the consoleCredentials work, generate a jwt with claims
|
2022-02-21 21:42:18 -08:00
|
|
|
token, err := auth.NewEncryptedTokenForClient(&tokens, credentials.GetAccountAccessKey(), sessionFeatures)
|
2020-04-22 23:43:17 -07:00
|
|
|
if err != nil {
|
2021-06-04 11:35:55 -07:00
|
|
|
LogError("error authenticating user: %v", err)
|
2022-04-28 12:55:06 -07:00
|
|
|
return nil, ErrInvalidLogin
|
2020-04-22 23:43:17 -07:00
|
|
|
}
|
2020-10-19 15:32:21 -07:00
|
|
|
return &token, nil
|
2020-04-01 18:18:57 -07:00
|
|
|
}
|
|
|
|
|
|
2022-04-11 20:01:49 -07:00
|
|
|
// getAccountInfo will return the current user information
|
|
|
|
|
func getAccountInfo(ctx context.Context, client MinioAdmin) (*madmin.AccountInfo, error) {
|
2021-07-19 11:48:50 -07:00
|
|
|
accountInfo, err := client.AccountInfo(ctx)
|
2020-05-04 16:18:04 -07:00
|
|
|
if err != nil {
|
2021-01-07 13:49:56 -06:00
|
|
|
return nil, err
|
2020-05-04 16:18:04 -07:00
|
|
|
}
|
2022-04-11 20:01:49 -07:00
|
|
|
return &accountInfo, nil
|
2020-05-04 16:18:04 -07:00
|
|
|
}
|
|
|
|
|
|
2021-10-12 21:25:02 -07:00
|
|
|
// getConsoleCredentials will return ConsoleCredentials interface
|
2023-06-14 12:36:48 -07:00
|
|
|
func getConsoleCredentials(accessKey, secretKey, clientIP string) (*ConsoleCredentials, error) {
|
|
|
|
|
creds, err := NewConsoleCredentials(accessKey, secretKey, GetMinIORegion(), clientIP)
|
2021-02-18 11:06:02 -08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2021-10-12 21:25:02 -07:00
|
|
|
return &ConsoleCredentials{
|
2021-07-19 11:48:50 -07:00
|
|
|
ConsoleCredentials: creds,
|
|
|
|
|
AccountAccessKey: accessKey,
|
2021-10-12 21:25:02 -07:00
|
|
|
}, nil
|
2020-12-07 17:11:08 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// getLoginResponse performs login() and serializes it to the handler's output
|
2023-08-16 14:18:08 -07:00
|
|
|
func getLoginResponse(params authApi.LoginParams) (*models.LoginResponse, *CodedAPIError) {
|
2022-04-28 12:55:06 -07:00
|
|
|
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
|
|
|
|
defer cancel()
|
|
|
|
|
lr := params.Body
|
2022-07-07 14:28:25 -05:00
|
|
|
var err error
|
|
|
|
|
var consoleCreds *ConsoleCredentials
|
|
|
|
|
// if we receive an STS we use that instead of the credentials
|
|
|
|
|
if lr.Sts != "" {
|
|
|
|
|
creds := credentials.NewStaticV4(lr.AccessKey, lr.SecretKey, lr.Sts)
|
|
|
|
|
consoleCreds = &ConsoleCredentials{
|
|
|
|
|
ConsoleCredentials: creds,
|
|
|
|
|
AccountAccessKey: lr.AccessKey,
|
|
|
|
|
}
|
2023-05-22 11:20:45 -06:00
|
|
|
|
|
|
|
|
credsVerificate, _ := creds.Get()
|
|
|
|
|
|
|
|
|
|
if credsVerificate.SessionToken == "" || credsVerificate.SecretAccessKey == "" || credsVerificate.AccessKeyID == "" {
|
|
|
|
|
return nil, ErrorWithContext(ctx, errors.New(401, "Invalid STS Params"))
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-07 14:28:25 -05:00
|
|
|
} else {
|
2023-06-14 12:36:48 -07:00
|
|
|
clientIP := getClientIP(params.HTTPRequest)
|
2022-07-07 14:28:25 -05:00
|
|
|
// prepare console credentials
|
2023-06-14 12:36:48 -07:00
|
|
|
consoleCreds, err = getConsoleCredentials(lr.AccessKey, lr.SecretKey, clientIP)
|
2022-07-07 14:28:25 -05:00
|
|
|
if err != nil {
|
2022-09-11 23:28:07 -07:00
|
|
|
return nil, ErrorWithContext(ctx, err, ErrInvalidLogin)
|
2022-07-07 14:28:25 -05:00
|
|
|
}
|
2020-12-07 17:11:08 -06:00
|
|
|
}
|
2022-07-07 14:28:25 -05:00
|
|
|
|
2022-02-21 21:42:18 -08:00
|
|
|
sf := &auth.SessionFeatures{}
|
|
|
|
|
if lr.Features != nil {
|
|
|
|
|
sf.HideMenu = lr.Features.HideMenu
|
|
|
|
|
}
|
|
|
|
|
sessionID, err := login(consoleCreds, sf)
|
2020-04-01 18:18:57 -07:00
|
|
|
if err != nil {
|
2022-09-11 23:28:07 -07:00
|
|
|
return nil, ErrorWithContext(ctx, err, ErrInvalidLogin)
|
2020-04-01 18:18:57 -07:00
|
|
|
}
|
|
|
|
|
// serialize output
|
|
|
|
|
loginResponse := &models.LoginResponse{
|
|
|
|
|
SessionID: *sessionID,
|
|
|
|
|
}
|
|
|
|
|
return loginResponse, nil
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-06 09:53:01 -08:00
|
|
|
// isKubernetes returns true if minio is running in kubernetes.
|
|
|
|
|
func isKubernetes() bool {
|
|
|
|
|
// Kubernetes env used to validate if we are
|
|
|
|
|
// indeed running inside a kubernetes pod
|
|
|
|
|
// is KUBERNETES_SERVICE_HOST
|
|
|
|
|
// https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/kubelet_pods.go#L541
|
|
|
|
|
return env.Get("KUBERNETES_SERVICE_HOST", "") != ""
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-26 00:34:17 -07:00
|
|
|
// getLoginDetailsResponse returns information regarding the Console authentication mechanism.
|
2023-12-26 12:38:42 -08:00
|
|
|
func getLoginDetailsResponse(params authApi.LoginDetailParams, openIDProviders oauth2.OpenIDPCfg) (ld *models.LoginDetails, apiErr *CodedAPIError) {
|
2020-05-01 08:38:52 -07:00
|
|
|
loginStrategy := models.LoginDetailsLoginStrategyForm
|
2022-10-20 20:08:54 -05:00
|
|
|
var redirectRules []*models.RedirectRule
|
|
|
|
|
|
2022-04-28 12:55:06 -07:00
|
|
|
r := params.HTTPRequest
|
2023-12-26 12:38:42 -08:00
|
|
|
|
2022-09-03 19:02:48 +03:00
|
|
|
var loginDetails *models.LoginDetails
|
2023-12-26 12:38:42 -08:00
|
|
|
if len(openIDProviders) > 0 {
|
2020-05-01 08:38:52 -07:00
|
|
|
loginStrategy = models.LoginDetailsLoginStrategyRedirect
|
2023-12-26 12:38:42 -08:00
|
|
|
}
|
2022-10-20 20:08:54 -05:00
|
|
|
|
2023-12-26 12:38:42 -08:00
|
|
|
for name, provider := range openIDProviders {
|
|
|
|
|
// initialize new oauth2 client
|
2022-10-20 20:08:54 -05:00
|
|
|
|
2024-05-01 09:46:35 -07:00
|
|
|
oauth2Client, err := provider.GetOauth2Provider(name, nil, r, GetConsoleHTTPClient(getClientIP(params.HTTPRequest)))
|
2023-12-26 12:38:42 -08:00
|
|
|
if err != nil {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2022-10-20 20:08:54 -05:00
|
|
|
|
2023-12-26 12:38:42 -08:00
|
|
|
// Validate user against IDP
|
|
|
|
|
identityProvider := &auth.IdentityProvider{
|
|
|
|
|
KeyFunc: provider.GetStateKeyFunc(),
|
|
|
|
|
Client: oauth2Client,
|
|
|
|
|
}
|
2023-03-07 16:10:21 -06:00
|
|
|
|
2023-12-26 12:38:42 -08:00
|
|
|
displayName := fmt.Sprintf("Login with SSO (%s)", name)
|
|
|
|
|
serviceType := ""
|
2023-03-07 16:10:21 -06:00
|
|
|
|
2023-12-26 12:38:42 -08:00
|
|
|
if provider.DisplayName != "" {
|
|
|
|
|
displayName = provider.DisplayName
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if provider.RoleArn != "" {
|
|
|
|
|
splitRoleArn := strings.Split(provider.RoleArn, ":")
|
|
|
|
|
|
|
|
|
|
if len(splitRoleArn) > 2 {
|
|
|
|
|
serviceType = splitRoleArn[2]
|
2022-09-03 19:02:48 +03:00
|
|
|
}
|
2023-12-26 12:38:42 -08:00
|
|
|
}
|
2022-10-20 20:08:54 -05:00
|
|
|
|
2023-12-26 12:38:42 -08:00
|
|
|
redirectRule := models.RedirectRule{
|
|
|
|
|
Redirect: identityProvider.GenerateLoginURL(),
|
|
|
|
|
DisplayName: displayName,
|
|
|
|
|
ServiceType: serviceType,
|
2020-05-01 08:38:52 -07:00
|
|
|
}
|
2023-12-26 12:38:42 -08:00
|
|
|
|
|
|
|
|
redirectRules = append(redirectRules, &redirectRule)
|
2020-05-01 08:38:52 -07:00
|
|
|
}
|
2023-12-26 12:38:42 -08:00
|
|
|
|
|
|
|
|
if len(openIDProviders) > 0 && len(redirectRules) == 0 {
|
|
|
|
|
loginStrategy = models.LoginDetailsLoginStrategyForm
|
|
|
|
|
// No IDP configured fallback to username/password
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-03 19:02:48 +03:00
|
|
|
loginDetails = &models.LoginDetails{
|
2020-05-01 08:38:52 -07:00
|
|
|
LoginStrategy: loginStrategy,
|
2022-10-20 20:08:54 -05:00
|
|
|
RedirectRules: redirectRules,
|
2022-12-06 09:53:01 -08:00
|
|
|
IsK8S: isKubernetes(),
|
2023-05-03 11:36:41 -06:00
|
|
|
AnimatedLogin: getConsoleAnimatedLogin(),
|
2020-05-01 08:38:52 -07:00
|
|
|
}
|
2023-12-26 12:38:42 -08:00
|
|
|
|
2020-05-01 08:38:52 -07:00
|
|
|
return loginDetails, nil
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-07 13:49:56 -06:00
|
|
|
// verifyUserAgainstIDP will verify user identity against the configured IDP and return MinIO credentials
|
|
|
|
|
func verifyUserAgainstIDP(ctx context.Context, provider auth.IdentityProviderI, code, state string) (*credentials.Credentials, error) {
|
|
|
|
|
userCredentials, err := provider.VerifyIdentity(ctx, code, state)
|
2020-05-01 08:38:52 -07:00
|
|
|
if err != nil {
|
2021-06-04 11:35:55 -07:00
|
|
|
LogError("error validating user identity against idp: %v", err)
|
2022-10-20 20:08:54 -05:00
|
|
|
return nil, err
|
2020-05-01 08:38:52 -07:00
|
|
|
}
|
2021-01-07 13:49:56 -06:00
|
|
|
return userCredentials, nil
|
2020-05-01 08:38:52 -07:00
|
|
|
}
|
|
|
|
|
|
2023-08-16 14:18:08 -07:00
|
|
|
func getLoginOauth2AuthResponse(params authApi.LoginOauth2AuthParams, openIDProviders oauth2.OpenIDPCfg) (*models.LoginResponse, *CodedAPIError) {
|
2022-04-28 12:55:06 -07:00
|
|
|
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
2020-11-30 14:24:30 -08:00
|
|
|
defer cancel()
|
2022-04-28 12:55:06 -07:00
|
|
|
r := params.HTTPRequest
|
|
|
|
|
lr := params.Body
|
2022-10-20 20:08:54 -05:00
|
|
|
|
2023-12-26 12:38:42 -08:00
|
|
|
if len(openIDProviders) > 0 {
|
2022-10-20 20:08:54 -05:00
|
|
|
// we read state
|
|
|
|
|
rState := *lr.State
|
|
|
|
|
|
|
|
|
|
decodedRState, err := base64.StdEncoding.DecodeString(rState)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, ErrorWithContext(ctx, err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var requestItems oauth2.LoginURLParams
|
2023-12-26 12:38:42 -08:00
|
|
|
if err = json.Unmarshal(decodedRState, &requestItems); err != nil {
|
2022-10-20 20:08:54 -05:00
|
|
|
return nil, ErrorWithContext(ctx, err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IDPName := requestItems.IDPName
|
|
|
|
|
state := requestItems.State
|
2023-06-14 12:36:48 -07:00
|
|
|
|
2023-12-26 12:38:42 -08:00
|
|
|
providerCfg, ok := openIDProviders[IDPName]
|
|
|
|
|
if !ok {
|
|
|
|
|
return nil, ErrorWithContext(ctx, fmt.Errorf("selected IDP %s does not exist", IDPName))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Initialize new identity provider with new oauth2Client per IDPName
|
2024-05-01 09:46:35 -07:00
|
|
|
oauth2Client, err := providerCfg.GetOauth2Provider(IDPName, nil, r,
|
|
|
|
|
GetConsoleHTTPClient(getClientIP(params.HTTPRequest)))
|
2020-05-01 08:38:52 -07:00
|
|
|
if err != nil {
|
2022-04-28 12:55:06 -07:00
|
|
|
return nil, ErrorWithContext(ctx, err)
|
2020-05-01 08:38:52 -07:00
|
|
|
}
|
2022-10-20 20:08:54 -05:00
|
|
|
|
2022-09-23 08:30:45 -07:00
|
|
|
identityProvider := auth.IdentityProvider{
|
2022-10-20 20:08:54 -05:00
|
|
|
KeyFunc: providerCfg.GetStateKeyFunc(),
|
2022-09-23 08:30:45 -07:00
|
|
|
Client: oauth2Client,
|
2022-10-20 20:08:54 -05:00
|
|
|
RoleARN: providerCfg.RoleArn,
|
2022-09-23 08:30:45 -07:00
|
|
|
}
|
2020-05-01 08:38:52 -07:00
|
|
|
// Validate user against IDP
|
2022-10-20 20:08:54 -05:00
|
|
|
userCredentials, err := verifyUserAgainstIDP(ctx, identityProvider, *lr.Code, state)
|
2020-05-01 08:38:52 -07:00
|
|
|
if err != nil {
|
2022-04-28 12:55:06 -07:00
|
|
|
return nil, ErrorWithContext(ctx, err)
|
2020-05-01 08:38:52 -07:00
|
|
|
}
|
2021-01-07 13:49:56 -06:00
|
|
|
// initialize admin client
|
|
|
|
|
// login user against console and generate session token
|
2021-07-19 11:48:50 -07:00
|
|
|
token, err := login(&ConsoleCredentials{
|
|
|
|
|
ConsoleCredentials: userCredentials,
|
|
|
|
|
AccountAccessKey: "",
|
2022-02-21 21:42:18 -08:00
|
|
|
}, nil)
|
2020-05-01 08:38:52 -07:00
|
|
|
if err != nil {
|
2022-04-28 12:55:06 -07:00
|
|
|
return nil, ErrorWithContext(ctx, err)
|
2020-05-01 08:38:52 -07:00
|
|
|
}
|
|
|
|
|
// serialize output
|
|
|
|
|
loginResponse := &models.LoginResponse{
|
2022-12-05 18:14:41 -06:00
|
|
|
SessionID: *token,
|
|
|
|
|
IDPRefreshToken: identityProvider.Client.RefreshToken,
|
2020-05-01 08:38:52 -07:00
|
|
|
}
|
|
|
|
|
return loginResponse, nil
|
2020-04-01 18:18:57 -07:00
|
|
|
}
|
2022-04-28 12:55:06 -07:00
|
|
|
return nil, ErrorWithContext(ctx, ErrDefault)
|
2020-04-01 18:18:57 -07:00
|
|
|
}
|