Added frontend components to control certificates and the like for SSO
This commit is contained in:
@@ -857,6 +857,7 @@ func handleInfo(resp http.ResponseWriter, request *http.Request) {
|
||||
userInfo, err := shuffle.HandleApiAuthentication(resp, request)
|
||||
if err != nil {
|
||||
log.Printf("[WARNING] Api authentication failed in handleInfo: %s", err)
|
||||
|
||||
resp.WriteHeader(401)
|
||||
resp.Write([]byte(`{"success": false}`))
|
||||
return
|
||||
@@ -1177,8 +1178,10 @@ func checkAdminLogin(resp http.ResponseWriter, request *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
//ssoUrl = org.SSOConfig.SOSOEntrypoint
|
||||
redirectUri := shuffle.SSOUrl
|
||||
resp.WriteHeader(200)
|
||||
resp.Write([]byte(fmt.Sprintf(`{"success": true, "reason": "redirect"}`)))
|
||||
resp.Write([]byte(fmt.Sprintf(`{"success": true, "reason": "redirect", "sso_url": "%s"}`, redirectUri)))
|
||||
}
|
||||
|
||||
func handleLogin(resp http.ResponseWriter, request *http.Request) {
|
||||
@@ -5866,7 +5869,7 @@ func initHandlers() {
|
||||
// Docker orborus specific - downloads an image
|
||||
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/login_sso", shuffle.HandleSSO).Methods("GET", "POST", "OPTIONS")
|
||||
r.HandleFunc("/api/v1/login_sso", shuffle.HandleSSO).Methods("POST", "OPTIONS")
|
||||
|
||||
// Important for email, IDS etc. Create this by:
|
||||
// PS: For cloud, this has to use cloud storage.
|
||||
|
||||
@@ -36,6 +36,8 @@ const OrgHeader = (props) => {
|
||||
const [appDownloadBranch, setAppDownloadBranch] = React.useState(selectedOrganization.defaults === undefined ? defaultBranch : selectedOrganization.defaults.app_download_branch === undefined || selectedOrganization.defaults.app_download_branch.length === 0 ? defaultBranch : selectedOrganization.defaults.app_download_branch)
|
||||
const [workflowDownloadUrl, setWorkflowDownloadUrl] = React.useState(selectedOrganization.defaults === undefined ? "https://github.com/frikky/shuffle-apps" : selectedOrganization.defaults.workflow_download_repo === undefined || selectedOrganization.defaults.workflow_download_repo.length === 0 ? "https://github.com/frikky/shuffle-workflows" : selectedOrganization.defaults.workflow_download_repo)
|
||||
const [workflowDownloadBranch, setWorkflowDownloadBranch] = React.useState(selectedOrganization.defaults === undefined ? defaultBranch : selectedOrganization.defaults.workflow_download_branch === undefined || selectedOrganization.defaults.workflow_download_branch.length === 0 ? defaultBranch : selectedOrganization.defaults.workflow_download_branch)
|
||||
const [ssoEntrypoint, setSsoEntrypoint] = React.useState(selectedOrganization.sso_config === undefined ? "" : selectedOrganization.sso_config.sso_entrypoint === undefined || selectedOrganization.sso_config.sso_entrypoint.length === 0 ? "" : selectedOrganization.sso_config.sso_entrypoint)
|
||||
const [ssoCertificate, setSsoCertificate] = React.useState(selectedOrganization.sso_config === undefined ? "" : selectedOrganization.sso_config.sso_certificate === undefined || selectedOrganization.sso_config.sso_certificate.length === 0 ? "" : selectedOrganization.sso_config.sso_certificate)
|
||||
|
||||
const [file, setFile] = React.useState("")
|
||||
const [fileBase64, setFileBase64] = React.useState(selectedOrganization.image)
|
||||
@@ -67,13 +69,14 @@ const OrgHeader = (props) => {
|
||||
}
|
||||
}
|
||||
|
||||
const handleEditOrg = (name, description, orgId, image, defaults) => {
|
||||
const handleEditOrg = (name, description, orgId, image, defaults, sso_config) => {
|
||||
const data = {
|
||||
"name": name,
|
||||
"description": description,
|
||||
"org_id": orgId,
|
||||
"image": image,
|
||||
"defaults": defaults,
|
||||
"sso_config": sso_config,
|
||||
}
|
||||
|
||||
const url = globalUrl + `/api/v1/orgs/${selectedOrganization.id}`;
|
||||
@@ -111,19 +114,25 @@ const OrgHeader = (props) => {
|
||||
}
|
||||
|
||||
const orgSaveButton =
|
||||
<Button
|
||||
style={{ width: 150, height: 55, flex: 1 }}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={() => handleEditOrg(orgName, orgDescription, selectedOrganization.id, selectedOrganization.image, {
|
||||
"app_download_repo": appDownloadUrl,
|
||||
"app_download_branch": appDownloadBranch,
|
||||
"workflow_download_repo": workflowDownloadUrl,
|
||||
"workflow_download_branch": workflowDownloadBranch,
|
||||
})}
|
||||
>
|
||||
<SaveIcon />
|
||||
</Button>
|
||||
<Tooltip title="Save any unsaved data" placement="bottom">
|
||||
<Button
|
||||
style={{ width: 150, height: 55, flex: 1 }}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={() => handleEditOrg(orgName, orgDescription, selectedOrganization.id, selectedOrganization.image, {
|
||||
"app_download_repo": appDownloadUrl,
|
||||
"app_download_branch": appDownloadBranch,
|
||||
"workflow_download_repo": workflowDownloadUrl,
|
||||
"workflow_download_branch": workflowDownloadBranch,
|
||||
},
|
||||
{
|
||||
"sso_entrypoint": ssoEntrypoint,
|
||||
"sso_certificate": ssoCertificate,
|
||||
})}
|
||||
>
|
||||
<SaveIcon />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
|
||||
var imageData = file.length > 0 ? file : fileBase64
|
||||
imageData = imageData === undefined || imageData.length === 0 ? defaultImage : imageData
|
||||
@@ -337,6 +346,69 @@ const OrgHeader = (props) => {
|
||||
/>
|
||||
</span>
|
||||
</Grid>
|
||||
<Grid item xs={6} style={{}}>
|
||||
<span>
|
||||
<Typography>
|
||||
SSO Entrypoint
|
||||
</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
|
||||
</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>
|
||||
{/*
|
||||
<span style={{textAlign: "center"}}>
|
||||
{expanded ?
|
||||
|
||||
@@ -34,6 +34,7 @@ const LoginDialog = props => {
|
||||
const [firstRequest, setFirstRequest] = useState(true);
|
||||
const [loginLoading, setLoginLoading] = useState(false);
|
||||
const [loginViewLoading, setLoginViewLoading] = useState(false);
|
||||
const [ssoUrl, setSSOUrl] = useState("")
|
||||
|
||||
// Used to swap from login to register. True = login, false = register
|
||||
|
||||
@@ -62,6 +63,10 @@ const LoginDialog = props => {
|
||||
if (responseJson["success"] === false) {
|
||||
setLoginInfo(responseJson["reason"])
|
||||
} else {
|
||||
if (responseJson.sso_url !== undefined && responseJson.sso_url !== null) {
|
||||
setSSOUrl(responseJson.sso_url)
|
||||
}
|
||||
|
||||
if (loginViewLoading) {
|
||||
setLoginViewLoading(false)
|
||||
checkLogin()
|
||||
@@ -306,17 +311,21 @@ const LoginDialog = props => {
|
||||
<div style={{ marginTop: "10px" }}>
|
||||
{loginInfo}
|
||||
</div>
|
||||
<Typography style={{textAlign: "center", }}>
|
||||
Or
|
||||
</Typography>
|
||||
<div style={{textAlign: "center", margin: 10, }}>
|
||||
<Button fullWidth color="secondary" variant="outlined" type="button" style={{ flex: "1", marginTop: 5}} onClick={() => {
|
||||
console.log("CLICK")
|
||||
window.location = "https://dev-23367303.okta.com/app/dev-23367303_shuffletest_1/exk1vg1j7bYUYEG0k5d7/sso/saml"
|
||||
}}>
|
||||
Use SSO
|
||||
</Button>
|
||||
</div>
|
||||
{ssoUrl !== undefined && ssoUrl !== null && ssoUrl.length > 0 ?
|
||||
<div>
|
||||
<Typography style={{textAlign: "center", }}>
|
||||
Or
|
||||
</Typography>
|
||||
<div style={{textAlign: "center", margin: 10, }}>
|
||||
<Button fullWidth color="secondary" variant="outlined" type="button" style={{ flex: "1", marginTop: 5}} onClick={() => {
|
||||
console.log("CLICK")
|
||||
window.location = ssoUrl
|
||||
}}>
|
||||
Use SSO
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
: null}
|
||||
</form>
|
||||
}
|
||||
</Paper>
|
||||
|
||||
Reference in New Issue
Block a user