diff --git a/models/login_details.go b/models/login_details.go
index 35ca1fead..53b319889 100644
--- a/models/login_details.go
+++ b/models/login_details.go
@@ -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
diff --git a/operatorapi/embedded_spec.go b/operatorapi/embedded_spec.go
index 5fd059701..8e4ef8429 100644
--- a/operatorapi/embedded_spec.go
+++ b/operatorapi/embedded_spec.go
@@ -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"
+ }
}
}
},
diff --git a/operatorapi/login.go b/operatorapi/login.go
index 661f6a5e1..16ac0c8db 100644
--- a/operatorapi/login.go
+++ b/operatorapi/login.go
@@ -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{
diff --git a/portal-ui/src/screens/LoginPage/LoginPage.tsx b/portal-ui/src/screens/LoginPage/LoginPage.tsx
index ec614a69b..a3203964d 100644
--- a/portal-ui/src/screens/LoginPage/LoginPage.tsx
+++ b/portal-ui/src/screens/LoginPage/LoginPage.tsx
@@ -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 = (
-
+ if (loginStrategy.redirect.length > 1) {
+ loginComponent = (
+
+ Login with SSO:
+
+
+ );
+ } else if (loginStrategy.redirect.length === 1) {
+ loginComponent = (
-
- );
+ );
+ } else {
+ loginComponent = (
+
+ Cannot retrieve redirect from login strategy
+
+ );
+ }
break;
}
case loginStrategyType.serviceAccount: {
diff --git a/portal-ui/src/screens/LoginPage/loginSlice.ts b/portal-ui/src/screens/LoginPage/loginSlice.ts
index 0f3d03cfe..13641fc40 100644
--- a/portal-ui/src/screens/LoginPage/loginSlice.ts
+++ b/portal-ui/src/screens/LoginPage/loginSlice.ts
@@ -50,7 +50,8 @@ const initialState: LoginState = {
jwt: "",
loginStrategy: {
loginStrategy: loginStrategyType.unknown,
- redirect: "",
+ redirect: [],
+ displayNames: [],
},
loginSending: false,
loadingFetchConfiguration: true,
diff --git a/portal-ui/src/screens/LoginPage/types.ts b/portal-ui/src/screens/LoginPage/types.ts
index 008d6408c..5a8301741 100644
--- a/portal-ui/src/screens/LoginPage/types.ts
+++ b/portal-ui/src/screens/LoginPage/types.ts
@@ -16,7 +16,8 @@
export interface ILoginDetails {
loginStrategy: loginStrategyType;
- redirect: string;
+ redirect: string[];
+ displayNames: string[];
isDirectPV?: boolean;
}
diff --git a/restapi/embedded_spec.go b/restapi/embedded_spec.go
index f79329c86..13032c538 100644
--- a/restapi/embedded_spec.go
+++ b/restapi/embedded_spec.go
@@ -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"
+ }
}
}
},
diff --git a/restapi/user_login.go b/restapi/user_login.go
index f304d0b81..29c33baea 100644
--- a/restapi/user_login.go
+++ b/restapi/user_login.go
@@ -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
}
diff --git a/sso-integration/dex-requests.py b/sso-integration/dex-requests.py
index d9d8b4a60..8f9aa8304 100644
--- a/sso-integration/dex-requests.py
+++ b/sso-integration/dex-requests.py
@@ -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])
diff --git a/sso-integration/sso_test.go b/sso-integration/sso_test.go
index e87e5b448..bfee20fbc 100644
--- a/sso-integration/sso_test.go
+++ b/sso-integration/sso_test.go
@@ -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 {
diff --git a/swagger-console.yml b/swagger-console.yml
index 4ba803828..125b2e2b6 100644
--- a/swagger-console.yml
+++ b/swagger-console.yml
@@ -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:
diff --git a/swagger-operator.yml b/swagger-operator.yml
index d3842e3b2..deb03957c 100644
--- a/swagger-operator.yml
+++ b/swagger-operator.yml
@@ -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