Add support for Multiple IDPs on Login screen (#2258)
This commit is contained in:
@@ -37,6 +37,9 @@ import (
|
||||
// swagger:model loginDetails
|
||||
type LoginDetails struct {
|
||||
|
||||
// display names
|
||||
DisplayNames []string `json:"displayNames"`
|
||||
|
||||
// is direct p v
|
||||
IsDirectPV bool `json:"isDirectPV,omitempty"`
|
||||
|
||||
@@ -45,7 +48,7 @@ type LoginDetails struct {
|
||||
LoginStrategy string `json:"loginStrategy,omitempty"`
|
||||
|
||||
// redirect
|
||||
Redirect string `json:"redirect,omitempty"`
|
||||
Redirect []string `json:"redirect"`
|
||||
}
|
||||
|
||||
// Validate validates this login details
|
||||
|
||||
@@ -3530,6 +3530,12 @@ func init() {
|
||||
"loginDetails": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"displayNames": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"isDirectPV": {
|
||||
"type": "boolean"
|
||||
},
|
||||
@@ -3543,7 +3549,10 @@ func init() {
|
||||
]
|
||||
},
|
||||
"redirect": {
|
||||
"type": "string"
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -9434,6 +9443,12 @@ func init() {
|
||||
"loginDetails": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"displayNames": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"isDirectPV": {
|
||||
"type": "boolean"
|
||||
},
|
||||
@@ -9447,7 +9462,10 @@ func init() {
|
||||
]
|
||||
},
|
||||
"redirect": {
|
||||
"type": "string"
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -101,7 +101,7 @@ func getLoginDetailsResponse(params authApi.LoginDetailParams) (*models.LoginDet
|
||||
r := params.HTTPRequest
|
||||
|
||||
loginStrategy := models.LoginDetailsLoginStrategyServiceDashAccount
|
||||
redirectURL := ""
|
||||
redirectURL := []string{}
|
||||
|
||||
if oauth2.IsIDPEnabled() {
|
||||
loginStrategy = models.LoginDetailsLoginStrategyRedirectDashServiceDashAccount
|
||||
@@ -112,7 +112,7 @@ func getLoginDetailsResponse(params authApi.LoginDetailParams) (*models.LoginDet
|
||||
}
|
||||
// Validate user against IDP
|
||||
identityProvider := &auth.IdentityProvider{Client: oauth2Client}
|
||||
redirectURL = identityProvider.GenerateLoginURL()
|
||||
redirectURL = append(redirectURL, identityProvider.GenerateLoginURL())
|
||||
}
|
||||
|
||||
loginDetails := &models.LoginDetails{
|
||||
|
||||
@@ -17,13 +17,20 @@
|
||||
import React, { useEffect } from "react";
|
||||
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { Box, InputAdornment, LinearProgress } from "@mui/material";
|
||||
import {
|
||||
Box,
|
||||
InputAdornment,
|
||||
LinearProgress,
|
||||
Select,
|
||||
MenuItem,
|
||||
} from "@mui/material";
|
||||
import { Theme, useTheme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import makeStyles from "@mui/styles/makeStyles";
|
||||
import Button from "@mui/material/Button";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import { loginStrategyType } from "./types";
|
||||
import LogoutIcon from "../../icons/LogoutIcon";
|
||||
import RefreshIcon from "../../icons/RefreshIcon";
|
||||
import MainError from "../Console/Common/MainError/MainError";
|
||||
import {
|
||||
@@ -72,6 +79,37 @@ const useStyles = makeStyles((theme: Theme) =>
|
||||
boxShadow: "none",
|
||||
padding: "16px 30px",
|
||||
},
|
||||
loginSsoText: {
|
||||
fontWeight: "700",
|
||||
marginBottom: "15px",
|
||||
},
|
||||
ssoSelect: {
|
||||
width: "100%",
|
||||
fontSize: "13px",
|
||||
fontWeight: "700",
|
||||
color: "grey",
|
||||
},
|
||||
ssoMenuItem: {
|
||||
fontSize: "15px",
|
||||
fontWeight: "700",
|
||||
color: theme.palette.primary.light,
|
||||
"&.MuiMenuItem-divider:last-of-type": {
|
||||
borderBottom: "none",
|
||||
},
|
||||
"&.Mui-focusVisible": {
|
||||
backgroundColor: theme.palette.grey["100"],
|
||||
},
|
||||
},
|
||||
ssoLoginIcon: {
|
||||
height: "13px",
|
||||
marginRight: "25px",
|
||||
},
|
||||
ssoSubmit: {
|
||||
marginTop: "15px",
|
||||
"&:first-of-type": {
|
||||
marginTop: 0,
|
||||
},
|
||||
},
|
||||
separator: {
|
||||
marginLeft: 8,
|
||||
marginRight: 8,
|
||||
@@ -189,6 +227,9 @@ const useStyles = makeStyles((theme: Theme) =>
|
||||
},
|
||||
},
|
||||
},
|
||||
loginStrategyMessage: {
|
||||
textAlign: "center",
|
||||
},
|
||||
loadingLoginStrategy: {
|
||||
textAlign: "center",
|
||||
width: 40,
|
||||
@@ -298,21 +339,59 @@ const Login = () => {
|
||||
}
|
||||
case loginStrategyType.redirect:
|
||||
case loginStrategyType.redirectServiceAccount: {
|
||||
loginComponent = (
|
||||
<React.Fragment>
|
||||
if (loginStrategy.redirect.length > 1) {
|
||||
loginComponent = (
|
||||
<React.Fragment>
|
||||
<div className={classes.loginSsoText}>Login with SSO:</div>
|
||||
<Select
|
||||
id="ssoLogin"
|
||||
name="ssoLogin"
|
||||
data-test-id="sso-login"
|
||||
onChange={(e) => {
|
||||
if (e.target.value) {
|
||||
window.location.href = e.target.value as string;
|
||||
}
|
||||
}}
|
||||
displayEmpty
|
||||
className={classes.ssoSelect}
|
||||
renderValue={() => "Select Provider"}
|
||||
>
|
||||
{loginStrategy.redirect.map((r, idx) => (
|
||||
<MenuItem
|
||||
value={r}
|
||||
key={`sso-login-option-${idx}`}
|
||||
className={classes.ssoMenuItem}
|
||||
divider={true}
|
||||
>
|
||||
<LogoutIcon className={classes.ssoLoginIcon} />
|
||||
{loginStrategy.displayNames[idx]}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</React.Fragment>
|
||||
);
|
||||
} else if (loginStrategy.redirect.length === 1) {
|
||||
loginComponent = (
|
||||
<Button
|
||||
key={`login-button`}
|
||||
component={"a"}
|
||||
href={loginStrategy.redirect}
|
||||
href={loginStrategy.redirect[0]}
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
id="sso-login"
|
||||
className={classes.submit}
|
||||
className={clsx(classes.submit, classes.ssoSubmit)}
|
||||
>
|
||||
Login with SSO
|
||||
{loginStrategy.displayNames[0]}
|
||||
</Button>
|
||||
</React.Fragment>
|
||||
);
|
||||
);
|
||||
} else {
|
||||
loginComponent = (
|
||||
<div className={classes.loginStrategyMessage}>
|
||||
Cannot retrieve redirect from login strategy
|
||||
</div>
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case loginStrategyType.serviceAccount: {
|
||||
|
||||
@@ -50,7 +50,8 @@ const initialState: LoginState = {
|
||||
jwt: "",
|
||||
loginStrategy: {
|
||||
loginStrategy: loginStrategyType.unknown,
|
||||
redirect: "",
|
||||
redirect: [],
|
||||
displayNames: [],
|
||||
},
|
||||
loginSending: false,
|
||||
loadingFetchConfiguration: true,
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
|
||||
export interface ILoginDetails {
|
||||
loginStrategy: loginStrategyType;
|
||||
redirect: string;
|
||||
redirect: string[];
|
||||
displayNames: string[];
|
||||
isDirectPV?: boolean;
|
||||
}
|
||||
|
||||
|
||||
@@ -5423,6 +5423,12 @@ func init() {
|
||||
"loginDetails": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"displayNames": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"loginStrategy": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
@@ -5433,7 +5439,10 @@ func init() {
|
||||
]
|
||||
},
|
||||
"redirect": {
|
||||
"type": "string"
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -12692,6 +12701,12 @@ func init() {
|
||||
"loginDetails": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"displayNames": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"loginStrategy": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
@@ -12702,7 +12717,10 @@ func init() {
|
||||
]
|
||||
},
|
||||
"redirect": {
|
||||
"type": "string"
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -149,23 +149,32 @@ func getLoginDetailsResponse(params authApi.LoginDetailParams, openIDProviders o
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
loginStrategy := models.LoginDetailsLoginStrategyForm
|
||||
redirectURL := ""
|
||||
redirectURL := []string{}
|
||||
displayNames := []string{}
|
||||
r := params.HTTPRequest
|
||||
if len(openIDProviders) > 0 {
|
||||
var loginDetails *models.LoginDetails
|
||||
if len(openIDProviders) >= 1 {
|
||||
loginStrategy = models.LoginDetailsLoginStrategyRedirect
|
||||
// initialize new oauth2 client
|
||||
oauth2Client, err := openIDProviders.NewOauth2ProviderClient(idpName, nil, r, GetConsoleHTTPClient())
|
||||
if err != nil {
|
||||
return nil, ErrorWithContext(ctx, err, ErrOauth2Provider)
|
||||
for name, provider := range openIDProviders {
|
||||
// initialize new oauth2 client
|
||||
oauth2Client, err := openIDProviders.NewOauth2ProviderClient(name, nil, r, GetConsoleHTTPClient())
|
||||
if err != nil {
|
||||
return nil, ErrorWithContext(ctx, err, ErrOauth2Provider)
|
||||
}
|
||||
// Validate user against IDP
|
||||
identityProvider := &auth.IdentityProvider{Client: oauth2Client}
|
||||
redirectURL = append(redirectURL, identityProvider.GenerateLoginURL())
|
||||
if provider.DisplayName != "" {
|
||||
displayNames = append(displayNames, provider.DisplayName)
|
||||
} else {
|
||||
displayNames = append(displayNames, "Login with SSO")
|
||||
}
|
||||
}
|
||||
// Validate user against IDP
|
||||
identityProvider := &auth.IdentityProvider{Client: oauth2Client}
|
||||
redirectURL = identityProvider.GenerateLoginURL()
|
||||
}
|
||||
|
||||
loginDetails := &models.LoginDetails{
|
||||
loginDetails = &models.LoginDetails{
|
||||
LoginStrategy: loginStrategy,
|
||||
Redirect: redirectURL,
|
||||
DisplayNames: displayNames,
|
||||
}
|
||||
return loginDetails, nil
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import pdb, sys, requests, pdb
|
||||
import pdb, sys, requests
|
||||
from bs4 import BeautifulSoup
|
||||
from urllib.parse import unquote
|
||||
|
||||
# Log in to Your Account via OpenLDAP Connector
|
||||
result = requests.get(sys.argv[1])
|
||||
|
||||
@@ -130,19 +130,20 @@ func TestMain(t *testing.T) {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
var jsonMap map[string]interface{}
|
||||
var jsonMap map[string][]interface{}
|
||||
json.Unmarshal(body, &jsonMap)
|
||||
fmt.Println(jsonMap["redirect"])
|
||||
redirect := jsonMap["redirect"]
|
||||
fmt.Println(jsonMap["redirect"][0])
|
||||
redirect := jsonMap["redirect"][0]
|
||||
redirectAsString := fmt.Sprint(redirect)
|
||||
fmt.Println(redirectAsString)
|
||||
|
||||
// execute script to get the code and state
|
||||
cmd, err := exec.Command("python3", "dex-requests.py", redirectAsString).Output()
|
||||
if err != nil {
|
||||
fmt.Printf("error %s", err)
|
||||
fmt.Printf("error %s\n", err)
|
||||
}
|
||||
urlOutput := string(cmd)
|
||||
fmt.Println("url output:", urlOutput)
|
||||
requestLoginBody := bytes.NewReader([]byte("login=dillon%40example.io&password=dillon"))
|
||||
|
||||
// parse url remove carriage return
|
||||
@@ -163,7 +164,9 @@ func TestMain(t *testing.T) {
|
||||
urlOutput,
|
||||
requestLoginBody,
|
||||
)
|
||||
fmt.Println(newRequestError)
|
||||
if newRequestError != nil {
|
||||
fmt.Println(newRequestError)
|
||||
}
|
||||
httpRequestLogin.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||
responseLogin, errorLogin := client.Do(httpRequestLogin)
|
||||
if errorLogin != nil {
|
||||
|
||||
@@ -3685,7 +3685,13 @@ definitions:
|
||||
type: string
|
||||
enum: [ form, redirect, service-account, redirect-service-account ]
|
||||
redirect:
|
||||
type: string
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
displayNames:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
loginOauth2AuthRequest:
|
||||
type: object
|
||||
required:
|
||||
|
||||
@@ -1589,7 +1589,13 @@ definitions:
|
||||
type: string
|
||||
enum: [ form, redirect, service-account, redirect-service-account ]
|
||||
redirect:
|
||||
type: string
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
displayNames:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
isDirectPV:
|
||||
type: boolean
|
||||
loginRequest:
|
||||
@@ -2600,7 +2606,6 @@ definitions:
|
||||
type: object
|
||||
requests:
|
||||
additionalProperties:
|
||||
additionalProperties:
|
||||
type: integer
|
||||
format: int64
|
||||
description: "Requests describes the minimum amount of compute
|
||||
|
||||
Reference in New Issue
Block a user