Added new test-build that includes OpenID connect to test with KeyCloak
This commit is contained in:
@@ -22,8 +22,9 @@ require (
|
|||||||
github.com/go-git/go-git/v5 v5.4.2
|
github.com/go-git/go-git/v5 v5.4.2
|
||||||
github.com/gorilla/mux v1.8.0
|
github.com/gorilla/mux v1.8.0
|
||||||
github.com/h2non/filetype v1.1.3
|
github.com/h2non/filetype v1.1.3
|
||||||
|
github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20170819232839-0fbfe93532da // indirect
|
||||||
github.com/satori/go.uuid v1.2.0
|
github.com/satori/go.uuid v1.2.0
|
||||||
github.com/shuffle/shuffle-shared v0.1.86
|
github.com/shuffle/shuffle-shared v0.1.94
|
||||||
go4.org v0.0.0-20201209231011-d4a079459e60 // indirect
|
go4.org v0.0.0-20201209231011-d4a079459e60 // indirect
|
||||||
golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce
|
golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce
|
||||||
google.golang.org/api v0.65.0
|
google.golang.org/api v0.65.0
|
||||||
|
|||||||
+71
-10
@@ -11,6 +11,7 @@ import (
|
|||||||
|
|
||||||
//"crypto/tls"
|
//"crypto/tls"
|
||||||
//"crypto/x509"
|
//"crypto/x509"
|
||||||
|
"encoding/base64"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
@@ -18,6 +19,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
@@ -53,6 +55,8 @@ import (
|
|||||||
"github.com/go-git/go-git/v5/plumbing"
|
"github.com/go-git/go-git/v5/plumbing"
|
||||||
"github.com/go-git/go-git/v5/storage/memory"
|
"github.com/go-git/go-git/v5/storage/memory"
|
||||||
|
|
||||||
|
//cv "github.com/nirasan/go-oauth-pkce-code-verifier"
|
||||||
|
|
||||||
//githttp "gopkg.in/src-d/go-git.v4/plumbing/transport/http"
|
//githttp "gopkg.in/src-d/go-git.v4/plumbing/transport/http"
|
||||||
|
|
||||||
// Random
|
// Random
|
||||||
@@ -1166,8 +1170,16 @@ func handleContact(resp http.ResponseWriter, request *http.Request) {
|
|||||||
resp.Write([]byte(fmt.Sprintf(`{"success": true, "message": "Thanks for reaching out. We will contact you soon!"}`)))
|
resp.Write([]byte(fmt.Sprintf(`{"success": true, "message": "Thanks for reaching out. We will contact you soon!"}`)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func verifier() (*shuffle.CodeVerifier, error) {
|
||||||
|
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
|
b := make([]byte, 32, 32)
|
||||||
|
for i := 0; i < 32; i++ {
|
||||||
|
b[i] = byte(r.Intn(255))
|
||||||
|
}
|
||||||
|
return shuffle.CreateCodeVerifierFromBytes(b)
|
||||||
|
}
|
||||||
|
|
||||||
func checkAdminLogin(resp http.ResponseWriter, request *http.Request) {
|
func checkAdminLogin(resp http.ResponseWriter, request *http.Request) {
|
||||||
log.Printf("In admin login request?")
|
|
||||||
cors := shuffle.HandleCors(resp, request)
|
cors := shuffle.HandleCors(resp, request)
|
||||||
if cors {
|
if cors {
|
||||||
return
|
return
|
||||||
@@ -1190,10 +1202,63 @@ func checkAdminLogin(resp http.ResponseWriter, request *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//ssoUrl = org.SSOConfig.SOSOEntrypoint
|
baseSSOUrl := ""
|
||||||
redirectUri := shuffle.SSOUrl
|
handled := []string{}
|
||||||
|
for _, user := range users {
|
||||||
|
if shuffle.ArrayContains(handled, user.ActiveOrg.Id) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
handled = append(handled, user.ActiveOrg.Id)
|
||||||
|
org, err := shuffle.GetOrg(ctx, user.ActiveOrg.Id)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[WARNING] Error getting org in admin check: %s", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// No childorg setup, only parent org
|
||||||
|
if len(org.ManagerOrgs) > 0 || len(org.CreatorOrg) > 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should run calculations
|
||||||
|
if len(org.SSOConfig.OpenIdAuthorization) > 0 {
|
||||||
|
log.Printf("[DEBUG] Found OpenID url (PKCE). Extra redirect check: %s", request.URL.String())
|
||||||
|
baseSSOUrl = org.SSOConfig.OpenIdAuthorization
|
||||||
|
|
||||||
|
codeChallenge := uuid.NewV4().String()
|
||||||
|
//h.Write([]byte(v.Value))
|
||||||
|
verifier, verifiererr := verifier()
|
||||||
|
if verifiererr == nil {
|
||||||
|
codeChallenge = verifier.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
//log.Printf("[DEBUG] Got challenge value %s (pre state)", codeChallenge)
|
||||||
|
|
||||||
|
redirectUrl := url.QueryEscape("http://localhost:5001/api/v1/login_openid")
|
||||||
|
state := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("org=%s&challenge=%s&redirect=%s", org.Id, codeChallenge, redirectUrl)))
|
||||||
|
|
||||||
|
// has to happen after initial value is stored
|
||||||
|
if verifiererr == nil {
|
||||||
|
codeChallenge = verifier.CodeChallengeS256()
|
||||||
|
}
|
||||||
|
|
||||||
|
//log.Printf("[DEBUG] Got challenge value %s (POST state)", codeChallenge)
|
||||||
|
|
||||||
|
baseSSOUrl += fmt.Sprintf("?client_id=%s&response_type=code&scope=openid&redirect_uri=%s&state=%s&code_challenge_method=S256&code_challenge=%s", org.SSOConfig.OpenIdClientId, redirectUrl, state, codeChallenge)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(org.SSOConfig.SSOEntrypoint) > 0 {
|
||||||
|
log.Printf("[DEBUG] Found SAML SSO url")
|
||||||
|
baseSSOUrl = org.SSOConfig.SSOEntrypoint
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] URL: %s", baseSSOUrl)
|
||||||
resp.WriteHeader(200)
|
resp.WriteHeader(200)
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": true, "reason": "redirect", "sso_url": "%s"}`, redirectUri)))
|
resp.Write([]byte(fmt.Sprintf(`{"success": true, "reason": "redirect", "sso_url": "%s"}`, baseSSOUrl)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleLogin(resp http.ResponseWriter, request *http.Request) {
|
func handleLogin(resp http.ResponseWriter, request *http.Request) {
|
||||||
@@ -3325,11 +3390,6 @@ func createFs(basepath, pathname string) (billy.Filesystem, error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
//if strings.Contains(path, "yaml") {
|
|
||||||
// log.Printf("PATH: %s -> %s", path, fullpath)
|
|
||||||
// //log.Printf("DATA: %s", string(srcData))
|
|
||||||
//}
|
|
||||||
|
|
||||||
dst, err := fs.Create(fullpath)
|
dst, err := fs.Create(fullpath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Dst error: %s", err)
|
log.Printf("Dst error: %s", err)
|
||||||
@@ -5882,7 +5942,8 @@ func initHandlers() {
|
|||||||
// Docker orborus specific - downloads an image
|
// Docker orborus specific - downloads an image
|
||||||
r.HandleFunc("/api/v1/get_docker_image", getDockerImage).Methods("POST", "OPTIONS")
|
r.HandleFunc("/api/v1/get_docker_image", getDockerImage).Methods("POST", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/migrate_database", migrateDatabase).Methods("POST", "OPTIONS")
|
r.HandleFunc("/api/v1/migrate_database", migrateDatabase).Methods("POST", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/login_sso", shuffle.HandleSSO).Methods("POST", "OPTIONS")
|
r.HandleFunc("/api/v1/login_sso", shuffle.HandleSSO).Methods("GET", "POST", "OPTIONS")
|
||||||
|
r.HandleFunc("/api/v1/login_openid", shuffle.HandleOpenId).Methods("GET", "OPTIONS")
|
||||||
|
|
||||||
// Important for email, IDS etc. Create this by:
|
// Important for email, IDS etc. Create this by:
|
||||||
// PS: For cloud, this has to use cloud storage.
|
// PS: For cloud, this has to use cloud storage.
|
||||||
|
|||||||
@@ -97,6 +97,30 @@ const OrgHeader = (props) => {
|
|||||||
? ""
|
? ""
|
||||||
: selectedOrganization.defaults.notification_workflow
|
: selectedOrganization.defaults.notification_workflow
|
||||||
);
|
);
|
||||||
|
const [openidClientId, setOpenidClientId] = React.useState(
|
||||||
|
selectedOrganization.sso_config === undefined
|
||||||
|
? ""
|
||||||
|
: selectedOrganization.sso_config.client_id === undefined ||
|
||||||
|
selectedOrganization.sso_config.client_id.length === 0
|
||||||
|
? ""
|
||||||
|
: selectedOrganization.sso_config.client_id
|
||||||
|
);
|
||||||
|
const [openidAuthorization, setOpenidAuthorization] = React.useState(
|
||||||
|
selectedOrganization.sso_config === undefined
|
||||||
|
? ""
|
||||||
|
: selectedOrganization.sso_config.openid_authorization === undefined ||
|
||||||
|
selectedOrganization.sso_config.openid_authorization.length === 0
|
||||||
|
? ""
|
||||||
|
: selectedOrganization.sso_config.openid_authorization
|
||||||
|
);
|
||||||
|
const [openidToken, setOpenidToken] = React.useState(
|
||||||
|
selectedOrganization.sso_config === undefined
|
||||||
|
? ""
|
||||||
|
: selectedOrganization.sso_config.openid_token=== undefined ||
|
||||||
|
selectedOrganization.sso_config.openid_token.length === 0
|
||||||
|
? ""
|
||||||
|
: selectedOrganization.sso_config.openidtoken_
|
||||||
|
)
|
||||||
|
|
||||||
const [file, setFile] = React.useState("");
|
const [file, setFile] = React.useState("");
|
||||||
const [fileBase64, setFileBase64] = React.useState(
|
const [fileBase64, setFileBase64] = React.useState(
|
||||||
@@ -145,6 +169,7 @@ const OrgHeader = (props) => {
|
|||||||
defaults,
|
defaults,
|
||||||
sso_config
|
sso_config
|
||||||
) => {
|
) => {
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
name: name,
|
name: name,
|
||||||
description: description,
|
description: description,
|
||||||
@@ -216,6 +241,9 @@ const OrgHeader = (props) => {
|
|||||||
{
|
{
|
||||||
sso_entrypoint: ssoEntrypoint,
|
sso_entrypoint: ssoEntrypoint,
|
||||||
sso_certificate: ssoCertificate,
|
sso_certificate: ssoCertificate,
|
||||||
|
client_id: openidClientId,
|
||||||
|
openid_authorization: openidAuthorization,
|
||||||
|
openid_token: openidToken,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -548,79 +576,200 @@ const OrgHeader = (props) => {
|
|||||||
</span>
|
</span>
|
||||||
</Grid>
|
</Grid>
|
||||||
)}
|
)}
|
||||||
<Grid item xs={6} style={{}}>
|
{isCloud ? null :
|
||||||
<span>
|
<Grid item xs={12} style={{marginTop: 50 }}>
|
||||||
<Typography>SSO Entrypoint (IdP)</Typography>
|
<Typography variant="h4" style={{textAlign: "center",}}>OpenID connect</Typography>
|
||||||
<TextField
|
<Grid container style={{marginTop: 10, }}>
|
||||||
required
|
<Grid item xs={4} style={{}}>
|
||||||
style={{
|
<span>
|
||||||
flex: "1",
|
<Typography>Client ID</Typography>
|
||||||
marginTop: "5px",
|
<TextField
|
||||||
marginRight: "15px",
|
required
|
||||||
backgroundColor: theme.palette.inputColor,
|
style={{
|
||||||
}}
|
flex: "1",
|
||||||
fullWidth={true}
|
marginTop: "5px",
|
||||||
type="name"
|
marginRight: "15px",
|
||||||
multiline={true}
|
backgroundColor: theme.palette.inputColor,
|
||||||
rows={2}
|
}}
|
||||||
disabled={
|
fullWidth={true}
|
||||||
selectedOrganization.manager_orgs !== undefined &&
|
type="name"
|
||||||
selectedOrganization.manager_orgs !== null &&
|
multiline={true}
|
||||||
selectedOrganization.manager_orgs.length > 0
|
rows={2}
|
||||||
}
|
disabled={
|
||||||
id="outlined-with-placeholder"
|
selectedOrganization.manager_orgs !== undefined &&
|
||||||
margin="normal"
|
selectedOrganization.manager_orgs !== null &&
|
||||||
variant="outlined"
|
selectedOrganization.manager_orgs.length > 0
|
||||||
placeholder="The entrypoint URL from your provider"
|
}
|
||||||
value={ssoEntrypoint}
|
id="outlined-with-placeholder"
|
||||||
onChange={(e) => {
|
margin="normal"
|
||||||
setSsoEntrypoint(e.target.value);
|
variant="outlined"
|
||||||
}}
|
placeholder="The OpenID client ID from the identity provider"
|
||||||
InputProps={{
|
value={openidClientId}
|
||||||
classes: {
|
onChange={(e) => {
|
||||||
notchedOutline: classes.notchedOutline,
|
setOpenidClientId(e.target.value);
|
||||||
},
|
}}
|
||||||
style: {
|
InputProps={{
|
||||||
color: "white",
|
classes: {
|
||||||
},
|
notchedOutline: classes.notchedOutline,
|
||||||
}}
|
},
|
||||||
/>
|
style: {
|
||||||
</span>
|
color: "white",
|
||||||
</Grid>
|
},
|
||||||
<Grid item xs={6} style={{}}>
|
}}
|
||||||
<span>
|
/>
|
||||||
<Typography>SSO Certificate (X509)</Typography>
|
</span>
|
||||||
<TextField
|
</Grid>
|
||||||
required
|
<Grid item xs={4} style={{}}>
|
||||||
style={{
|
<span>
|
||||||
flex: "1",
|
<Typography>Authorization URL</Typography>
|
||||||
marginTop: "5px",
|
<TextField
|
||||||
marginRight: "15px",
|
required
|
||||||
backgroundColor: theme.palette.inputColor,
|
style={{
|
||||||
}}
|
flex: "1",
|
||||||
fullWidth={true}
|
marginTop: "5px",
|
||||||
type="name"
|
marginRight: "15px",
|
||||||
id="outlined-with-placeholder"
|
backgroundColor: theme.palette.inputColor,
|
||||||
margin="normal"
|
}}
|
||||||
variant="outlined"
|
fullWidth={true}
|
||||||
multiline={true}
|
type="name"
|
||||||
rows={2}
|
id="outlined-with-placeholder"
|
||||||
placeholder="The X509 certificate to use"
|
margin="normal"
|
||||||
value={ssoCertificate}
|
variant="outlined"
|
||||||
onChange={(e) => {
|
multiline={true}
|
||||||
setSsoCertificate(e.target.value);
|
rows={2}
|
||||||
}}
|
placeholder="The OpenID authorization URL (usually ends with /authorize)"
|
||||||
InputProps={{
|
value={openidAuthorization}
|
||||||
classes: {
|
onChange={(e) => {
|
||||||
notchedOutline: classes.notchedOutline,
|
setOpenidAuthorization(e.target.value)
|
||||||
},
|
}}
|
||||||
style: {
|
InputProps={{
|
||||||
color: "white",
|
classes: {
|
||||||
},
|
notchedOutline: classes.notchedOutline,
|
||||||
}}
|
},
|
||||||
/>
|
style: {
|
||||||
</span>
|
color: "white",
|
||||||
</Grid>
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={4} style={{}}>
|
||||||
|
<span>
|
||||||
|
<Typography>Token URL</Typography>
|
||||||
|
<TextField
|
||||||
|
required
|
||||||
|
style={{
|
||||||
|
flex: "1",
|
||||||
|
marginTop: "5px",
|
||||||
|
marginRight: "15px",
|
||||||
|
backgroundColor: theme.palette.inputColor,
|
||||||
|
}}
|
||||||
|
fullWidth={true}
|
||||||
|
type="name"
|
||||||
|
id="outlined-with-placeholder"
|
||||||
|
margin="normal"
|
||||||
|
variant="outlined"
|
||||||
|
multiline={true}
|
||||||
|
rows={2}
|
||||||
|
placeholder="The OpenID token URL (usually ends with /token)"
|
||||||
|
value={openidToken}
|
||||||
|
onChange={(e) => {
|
||||||
|
setOpenidToken(e.target.value)
|
||||||
|
}}
|
||||||
|
InputProps={{
|
||||||
|
classes: {
|
||||||
|
notchedOutline: classes.notchedOutline,
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
color: "white",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
}
|
||||||
|
{isCloud ? null :
|
||||||
|
<Grid item xs={12} style={{marginTop: 50,}}>
|
||||||
|
<Typography variant="h4" style={{textAlign: "center",}}>SAML SSO (v1.1)</Typography>
|
||||||
|
<Grid container style={{marginTop: 10, }}>
|
||||||
|
<Grid item xs={6} style={{}}>
|
||||||
|
<span>
|
||||||
|
<Typography>SSO Entrypoint (IdP)</Typography>
|
||||||
|
<TextField
|
||||||
|
required
|
||||||
|
style={{
|
||||||
|
flex: "1",
|
||||||
|
marginTop: "5px",
|
||||||
|
marginRight: "15px",
|
||||||
|
backgroundColor: theme.palette.inputColor,
|
||||||
|
}}
|
||||||
|
fullWidth={true}
|
||||||
|
type="name"
|
||||||
|
multiline={true}
|
||||||
|
rows={2}
|
||||||
|
disabled={
|
||||||
|
selectedOrganization.manager_orgs !== undefined &&
|
||||||
|
selectedOrganization.manager_orgs !== null &&
|
||||||
|
selectedOrganization.manager_orgs.length > 0
|
||||||
|
}
|
||||||
|
id="outlined-with-placeholder"
|
||||||
|
margin="normal"
|
||||||
|
variant="outlined"
|
||||||
|
placeholder="The entrypoint URL from your provider"
|
||||||
|
value={ssoEntrypoint}
|
||||||
|
onChange={(e) => {
|
||||||
|
setSsoEntrypoint(e.target.value);
|
||||||
|
}}
|
||||||
|
InputProps={{
|
||||||
|
classes: {
|
||||||
|
notchedOutline: classes.notchedOutline,
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
color: "white",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={6} style={{}}>
|
||||||
|
<span>
|
||||||
|
<Typography>SSO Certificate (X509)</Typography>
|
||||||
|
<TextField
|
||||||
|
required
|
||||||
|
style={{
|
||||||
|
flex: "1",
|
||||||
|
marginTop: "5px",
|
||||||
|
marginRight: "15px",
|
||||||
|
backgroundColor: theme.palette.inputColor,
|
||||||
|
}}
|
||||||
|
fullWidth={true}
|
||||||
|
type="name"
|
||||||
|
id="outlined-with-placeholder"
|
||||||
|
margin="normal"
|
||||||
|
variant="outlined"
|
||||||
|
multiline={true}
|
||||||
|
rows={2}
|
||||||
|
placeholder="The X509 certificate to use"
|
||||||
|
value={ssoCertificate}
|
||||||
|
onChange={(e) => {
|
||||||
|
setSsoCertificate(e.target.value);
|
||||||
|
}}
|
||||||
|
InputProps={{
|
||||||
|
classes: {
|
||||||
|
notchedOutline: classes.notchedOutline,
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
color: "white",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
}
|
||||||
{/*
|
{/*
|
||||||
<span style={{textAlign: "center"}}>
|
<span style={{textAlign: "center"}}>
|
||||||
{expanded ?
|
{expanded ?
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/* eslint-disable react/no-multi-comp */
|
/* eslint-disable react/no-multi-comp */
|
||||||
import React, { useState } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { makeStyles } from "@material-ui/styles";
|
import { makeStyles } from "@material-ui/styles";
|
||||||
import { useInterval } from "react-powerhooks";
|
import { useInterval } from "react-powerhooks";
|
||||||
|
|
||||||
@@ -55,6 +55,7 @@ const LoginDialog = (props) => {
|
|||||||
const [MFAField, setMFAField] = useState(false);
|
const [MFAField, setMFAField] = useState(false);
|
||||||
const [MFAValue, setMFAValue] = useState("");
|
const [MFAValue, setMFAValue] = useState("");
|
||||||
|
|
||||||
|
|
||||||
// Used to swap from login to register. True = login, false = register
|
// Used to swap from login to register. True = login, false = register
|
||||||
|
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
@@ -468,6 +469,7 @@ const LoginDialog = (props) => {
|
|||||||
<div style={{ textAlign: "center", margin: 10 }}>
|
<div style={{ textAlign: "center", margin: 10 }}>
|
||||||
<Button
|
<Button
|
||||||
fullWidth
|
fullWidth
|
||||||
|
id="sso_button"
|
||||||
color="secondary"
|
color="secondary"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
type="button"
|
type="button"
|
||||||
@@ -491,6 +493,16 @@ const LoginDialog = (props) => {
|
|||||||
|
|
||||||
const loadedCheck = isLoaded ? <div>{basedata}</div> : <div></div>;
|
const loadedCheck = isLoaded ? <div>{basedata}</div> : <div></div>;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (ssoUrl !== undefined && ssoUrl !== null && ssoUrl.length > 0) {
|
||||||
|
//id="sso_button"
|
||||||
|
const ssoBtn = document.getElementById("sso_button");
|
||||||
|
if (ssoBtn !== undefined && ssoBtn !== null) {
|
||||||
|
console.log("SSO BTN: ", ssoBtn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [ssoUrl])
|
||||||
|
|
||||||
return <div>{loadedCheck}</div>;
|
return <div>{loadedCheck}</div>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user