#168: Added prototype of Oauth2 handler with example app

This commit is contained in:
frikky
2021-08-19 00:58:01 +02:00
parent 56185e53e2
commit 53b02e7c46
8 changed files with 235 additions and 19 deletions
+3 -1
View File
@@ -1529,6 +1529,8 @@ class AppBase:
#print(globals()) #print(globals())
print("Running liquid with data of length %d" % len(template)) print("Running liquid with data of length %d" % len(template))
run = Liquid(template, {'mode': 'python'}) run = Liquid(template, {'mode': 'python'})
# Can't handle self yet (?)
ret = run.render(**globals()) ret = run.render(**globals())
return ret return ret
#try: #try:
@@ -2059,7 +2061,7 @@ class AppBase:
#json_replacement = tmpitem.replace(actualitem[index][0], replacement, 1) #json_replacement = tmpitem.replace(actualitem[index][0], replacement, 1)
#print("AFTER POST replacement: %s" % json_replacement) #print("AFTER POST replacement: %s" % json_replacement)
#json_replacement = replacement json_replacement = replacement
try: try:
json_replacement = json.loads(replacement) json_replacement = json.loads(replacement)
except json.decoder.JSONDecodeError as e: except json.decoder.JSONDecodeError as e:
+1 -1
View File
@@ -2,7 +2,7 @@ module shuffle
go 1.13 go 1.13
//replace github.com/frikky/shuffle-shared => ../../../../git/shuffle-shared replace github.com/frikky/shuffle-shared => ../../../../git/shuffle-shared
//replace github.com/frikky/kin-openapi => ../../../../git/kin-openapi //replace github.com/frikky/kin-openapi => ../../../../git/kin-openapi
+30 -11
View File
@@ -1552,7 +1552,6 @@ func handleExecution(id string, workflow shuffle.Workflow, request *http.Request
} }
workflowExecution.ExecutionVariables = workflow.ExecutionVariables workflowExecution.ExecutionVariables = workflow.ExecutionVariables
if len(workflowExecution.Start) == 0 && len(workflowExecution.Workflow.Start) > 0 { if len(workflowExecution.Start) == 0 && len(workflowExecution.Workflow.Start) > 0 {
workflowExecution.Start = workflowExecution.Workflow.Start workflowExecution.Start = workflowExecution.Workflow.Start
} }
@@ -1621,20 +1620,40 @@ func handleExecution(id string, workflow shuffle.Workflow, request *http.Request
return shuffle.WorkflowExecution{}, fmt.Sprintf("Auth ID %s doesn't exist", action.AuthenticationId), errors.New(fmt.Sprintf("Auth ID %s doesn't exist", action.AuthenticationId)) return shuffle.WorkflowExecution{}, fmt.Sprintf("Auth ID %s doesn't exist", action.AuthenticationId), errors.New(fmt.Sprintf("Auth ID %s doesn't exist", action.AuthenticationId))
} }
// Rebuild params with the right data. This is to prevent issues on the frontend
newParams := []shuffle.WorkflowAppActionParameter{} newParams := []shuffle.WorkflowAppActionParameter{}
for _, param := range action.Parameters { if strings.ToLower(curAuth.Type) == "oauth2" {
log.Printf("\n\nShould replace auth parameters!!!\n\n")
for _, authparam := range curAuth.Fields { for _, param := range curAuth.Fields {
if param.Name == authparam.Key { newParams = append(newParams, shuffle.WorkflowAppActionParameter{
param.Value = authparam.Value Name: param.Key,
//log.Printf("Name: %s - value: %s", param.Name, param.Value) Value: param.Value,
//log.Printf("Name: %s - value: %s\n", param.Name, param.Value) })
break
}
} }
newParams = append(newParams, param) for _, param := range action.Parameters {
log.Printf("Param: %#v", param)
if param.Configuration {
continue
}
newParams = append(newParams, param)
}
} else {
// Rebuild params with the right data. This is to prevent issues on the frontend
for _, param := range action.Parameters {
for _, authparam := range curAuth.Fields {
if param.Name == authparam.Key {
param.Value = authparam.Value
//log.Printf("Name: %s - value: %s", param.Name, param.Value)
//log.Printf("Name: %s - value: %s\n", param.Name, param.Value)
break
}
}
newParams = append(newParams, param)
}
} }
action.Parameters = newParams action.Parameters = newParams
+2
View File
@@ -22,6 +22,7 @@ import AdminSetup from "./views/AdminSetup";
import Admin from "./views/Admin"; import Admin from "./views/Admin";
import Docs from "./views/Docs"; import Docs from "./views/Docs";
import Introduction from "./views/Introduction"; import Introduction from "./views/Introduction";
import SetAuthentication from "./views/SetAuthentication";
import LandingPageNew from "./views/LandingpageNew"; import LandingPageNew from "./views/LandingpageNew";
import LoginPage from "./views/LoginPage"; import LoginPage from "./views/LoginPage";
@@ -125,6 +126,7 @@ const App = (message, props) => {
<Route exact path="/docs" render={props => { window.location.pathname = "/docs/about" }} /> <Route exact path="/docs" render={props => { window.location.pathname = "/docs/about" }} />
<Route exact path="/introduction" render={props => <Introduction isLoaded={isLoaded} globalUrl={globalUrl} {...props} />} /> <Route exact path="/introduction" render={props => <Introduction isLoaded={isLoaded} globalUrl={globalUrl} {...props} />} />
<Route exact path="/introduction/:key" render={props => <Introduction isLoaded={isLoaded} globalUrl={globalUrl} {...props} />} /> <Route exact path="/introduction/:key" render={props => <Introduction isLoaded={isLoaded} globalUrl={globalUrl} {...props} />} />
<Route exact path="/set_authentication" render={props => <SetAuthentication userdata={userdata} isLoggedIn={isLoggedIn} setIsLoggedIn={setIsLoggedIn} register={true} isLoaded={isLoaded} globalUrl={globalUrl} setCookie={setCookie} cookies={cookies} {...props} />} />
<Route exact path="/" render={props => <LoginPage isLoggedIn={isLoggedIn} setIsLoggedIn={setIsLoggedIn} register={true} isLoaded={isLoaded} globalUrl={globalUrl} setCookie={setCookie} cookies={cookies} {...props} />} /> <Route exact path="/" render={props => <LoginPage isLoggedIn={isLoggedIn} setIsLoggedIn={setIsLoggedIn} register={true} isLoaded={isLoaded} globalUrl={globalUrl} setCookie={setCookie} cookies={cookies} {...props} />} />
</div> </div>
+37 -1
View File
@@ -46,7 +46,7 @@ const useStyles = makeStyles({
//) //)
const ParsedAction = (props) => { const ParsedAction = (props) => {
const {workflow, setWorkflow, setAction, setSelectedAction, setUpdate, appActionArguments, selectedApp, workflowExecutions, setSelectedResult, selectedAction, setSelectedApp, setSelectedTrigger, setSelectedEdge, setCurrentView, cy, setAuthenticationModalOpen,setVariablesModalOpen, setCodeModalOpen, selectedNameChange, rightsidebarStyle, showEnvironment, selectedActionEnvironment, environments, setNewSelectedAction, appApiViewStyle, globalUrl, setSelectedActionEnvironment, requiresAuthentication, hideExtraTypes, scrollConfig, setScrollConfig } = props const {workflow, setWorkflow, setAction, setSelectedAction, setUpdate, appActionArguments, selectedApp, workflowExecutions, setSelectedResult, selectedAction, setSelectedApp, setSelectedTrigger, setSelectedEdge, setCurrentView, cy, setAuthenticationModalOpen,setVariablesModalOpen, setCodeModalOpen, selectedNameChange, rightsidebarStyle, showEnvironment, selectedActionEnvironment, environments, setNewSelectedAction, appApiViewStyle, globalUrl, setSelectedActionEnvironment, requiresAuthentication, hideExtraTypes, scrollConfig, setScrollConfig, authenticationType, appAuthentication, getAppAuthentication } = props
const theme = useTheme(); const theme = useTheme();
const classes = useStyles() const classes = useStyles()
@@ -1389,6 +1389,42 @@ const ParsedAction = (props) => {
<Tooltip color="primary" title={"Add authentication option"} placement="top"> <Tooltip color="primary" title={"Add authentication option"} placement="top">
<span> <span>
<Button color="primary" style={{}} fullWidth variant="contained" onClick={() => { <Button color="primary" style={{}} fullWidth variant="contained" onClick={() => {
console.log(authenticationType)
if (authenticationType.type === "oauth2" && authenticationType.redirect_uri !== undefined && authenticationType.redirect_uri !== null) {
// FIXME: Sending client secret and senitive info like this may not be ok.
const client_id = "dae24316-4bec-4832-b660-4cba6dc2477b"
const client_secret = "._Qu3EvYY-OW_D57uy79qwEo.32qD6.l0z"
const authentication_url = "https://login.microsoftonline.com/common/oauth2/v2.0/token"
const resources = "UserAuthenticationMethod.ReadWrite.All"
const redirectUri = `http://${window.location.host}/set_authentication`
const state = `workflow_id%3D${workflow.id}%26reference_action_id%3d${selectedAction.app_id}%26app_name%3d${selectedAction.app_name}%26app_id%3d${selectedAction.app_id}%26app_version%3d${selectedAction.app_version}%26authentication_url%3d${authentication_url}%26scope%3d${resources}%26client_id%3d${client_id}%26client_secret%3d${client_secret}`
const url = `https://login.microsoftonline.com/common/oauth2/authorize?client_id=${client_id}&redirect_uri=${redirectUri}&response_type=code&scope=${resources}&state=${state}`
// &resource=https%3A%2F%2Fgraph.microsoft.com&
var newwin = window.open(url, "", "width=200,height=100")
console.log(newwin)
setTimeout(() => {
console.log(newwin)
console.log("CLOSED", newwin.closed)
}, 1000)
setTimeout(() => {
console.log(newwin)
console.log("CLOSED", newwin.closed)
if (newwin.closed) {
getAppAuthentication(true)
setTimeout(() => {
console.log("APPAUTH: ", appAuthentication)
}, 1500)
}
}, 10000)
return
//do {
//} while (
}
setAuthenticationModalOpen(true) setAuthenticationModalOpen(true)
}}> }}>
<AddIcon style={{marginRight: 10, }}/> Authenticate {selectedApp.name} <AddIcon style={{marginRight: 10, }}/> Authenticate {selectedApp.name}
+19 -4
View File
@@ -171,6 +171,7 @@ const AngularWorkflow = (props) => {
const [authenticationModalOpen, setAuthenticationModalOpen] = React.useState(false); const [authenticationModalOpen, setAuthenticationModalOpen] = React.useState(false);
const [conditionsModalOpen, setConditionsModalOpen] = React.useState(false); const [conditionsModalOpen, setConditionsModalOpen] = React.useState(false);
const [newVariableName, setNewVariableName] = React.useState(""); const [newVariableName, setNewVariableName] = React.useState("");
const [authenticationType, setAuthenticationType] = React.useState("");
const [newVariableDescription, setNewVariableDescription] = React.useState(""); const [newVariableDescription, setNewVariableDescription] = React.useState("");
const [newVariableValue, setNewVariableValue] = React.useState(""); const [newVariableValue, setNewVariableValue] = React.useState("");
const [workflowDone, setWorkflowDone] = React.useState(false) const [workflowDone, setWorkflowDone] = React.useState(false)
@@ -1944,9 +1945,19 @@ const AngularWorkflow = (props) => {
setSelectedAction(curaction) setSelectedAction(curaction)
//return //return
} else { } else {
console.log("AUTHENTICATION: ", curapp.authentication)
setAuthenticationType(curapp.authentication.type === "oauth2" && curapp.authentication.redirect_uri !== undefined && curapp.authentication.redirect_uri !== null ?
{
"type": "oauth2",
"redirect_uri": curapp.authentication.redirect_uri,
} : {
"type": ""
}
)
//console.log("AUTHENTICATION: ", curapp.authentication) const requiresAuth = curapp.authentication.required //&& ((curapp.authentication.parameters !== undefined && curapp.authentication.parameters !== null) || (curapp.authentication.type === "oauth2" && curapp.authentication.redirect_uri !== undefined && curapp.authentication.redirect_uri !== null))
setRequiresAuthentication(curapp.authentication.required && curapp.authentication.parameters !== undefined && curapp.authentication.parameters !== null) console.log("AUTHCHECK: ", requiresAuth)
setRequiresAuthentication(requiresAuth)
if (curapp.authentication.required) { if (curapp.authentication.required) {
//console.log("App requires auth.") //console.log("App requires auth.")
// Setup auth here :) // Setup auth here :)
@@ -7431,6 +7442,9 @@ const AngularWorkflow = (props) => {
<div id="rightside_actions" style={rightsidebarStyle}> <div id="rightside_actions" style={rightsidebarStyle}>
<ParsedAction <ParsedAction
id="rightside_subactions" id="rightside_subactions"
getAppAuthentication={getAppAuthentication}
appAuthentication={appAuthentication}
authenticationType={authenticationType}
scrollConfig={scrollConfig} scrollConfig={scrollConfig}
setScrollConfig={setScrollConfig} setScrollConfig={setScrollConfig}
selectedAction={selectedAction} selectedAction={selectedAction}
@@ -8138,7 +8152,7 @@ const AngularWorkflow = (props) => {
// //cf80fa70-65cf-4963-b474-b459a6dead81 // //cf80fa70-65cf-4963-b474-b459a6dead81
//} //}
console.log(selectedResult) //console.log(selectedResult)
const codePopoutModal = !codeModalOpen ? null : const codePopoutModal = !codeModalOpen ? null :
<Draggable <Draggable
onDrag={(e) => { onDrag={(e) => {
@@ -8709,10 +8723,11 @@ const AngularWorkflow = (props) => {
authenticationOption.label = selectedApp.name+" authentication" authenticationOption.label = selectedApp.name+" authentication"
} }
//console.log(
return ( return (
<div> <div>
<DialogContent> <DialogContent>
<a target="_blank" rel="norefferer" href="https://shuffler.io/docs/apps#authentication" style={{textDecoration: "none", color: "#f85a3e"}}>What is this?</a><div/> <a target="_blank" rel="norefferer" href="https://shuffler.io/docs/apps#authentication" style={{textDecoration: "none", color: "#f85a3e"}}>What is app authentication?</a><div/>
These are required fields for authenticating with {selectedApp.name} These are required fields for authenticating with {selectedApp.name}
<div style={{marginTop: 15}}/> <div style={{marginTop: 15}}/>
<b>Name - what is this used for?</b> <b>Name - what is this used for?</b>
+143
View File
@@ -0,0 +1,143 @@
import React, {useRef, useState, useEffect, useLayoutEffect} from 'react';
import { Typography, CircularProgress } from '@material-ui/core';
const SetAuthentication = (props) => {
const { globalUrl, isLoggedIn, isLoaded, userdata } = props;
const [firstRequest, setFirstRequest] = useState(true)
const [finished, setFinished] = useState(false)
const [response, setResponse] = useState("")
const [failed, setFailed] = useState(false)
if (firstRequest) {
setFirstRequest(false)
//code
//session_state
const urlSearchParams = new URLSearchParams(window.location.search);
const params = Object.fromEntries(urlSearchParams.entries());
const authenticationStore = []
var appAuthData = {
"label": "",
"app": {
"name": "",
"id": "",
"app_version": "",
},
"fields": [],
"type": "oauth2",
}
if (window !== undefined && window !== null) {
console.log(window.location)
appAuthData.fields.push({"key": "redirect_uri", "value": window.location.origin+window.location.pathname})
}
if (params.code !== undefined && params.code !== null) {
appAuthData.fields.push({"key": "code", "value": params.code})
}
if (params.session_state !== undefined && params.session_state !== null) {
appAuthData.fields.push({"key": "session_state", "value": params.session_state})
}
if (params.state !== undefined && params.state !== null) {
const paramsplit = params.state.split("&")
console.log(paramsplit)
for (var key in paramsplit) {
const query = paramsplit[key].split("=")
console.log(query)
if (query.length !== 2) {
console.log("INVALID QUERY: ", query)
continue
}
if (query[0] === "workflow_id") {
appAuthData.reference_workflow = query[1]
}
if (query[0] === "reference_action_id") {
//appAuthData.ReferenceWorkflow = query[1]
}
if (query[0] === "app_name") {
appAuthData.app.name = query[1]
appAuthData.label = "Oauth2 for "+query[1]
}
if (query[0] === "app_id") {
appAuthData.app.id = query[1]
}
if (query[0] === "app_version") {
appAuthData.app.app_version = query[1]
}
if (query[0] === "authentication_url") {
appAuthData.fields.push({"key": "authentication_url", "value": query[1]})
}
if (query[0] === "scope") {
appAuthData.fields.push({"key": "scope", "value": query[1]})
}
if (query[0] === "client_id") {
appAuthData.fields.push({"key": "client_id", "value": query[1]})
}
if (query[0] === "client_secret") {
appAuthData.fields.push({"key": "client_secret", "value": query[1]})
}
}
}
console.log(appAuthData)
fetch(globalUrl+"/api/v1/apps/authentication", {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
credentials: "include",
body: JSON.stringify(appAuthData),
})
.then((response) => {
if (response.status !== 200) {
console.log("Status not 200 for oauth2 authentication")
setFailed(true)
}
return response.json()
})
.then((responseJson) => {
//setUserSettings(responseJson)
console.log("Resp: ", responseJson)
setFinished(true)
setResponse(responseJson.reason)
setTimeout(() => {
window.close()
}, 1000)
})
.catch(error => {
console.log(error)
});
}
return (
<div style={{width: 1000, margin: "auto", itemAlign: "center",}}>
<Typography variant="h6" style={{marginLeft: "auto", marginRight: "auto", marginTop: 200, }}>
{!finished ? <CircularProgress /> : "DONE WITH AUTH - this will close soon!!"}
<div />
{failed ? "Failed setup. Error: " : ""} {response}
</Typography>
</div>
)
}
export default SetAuthentication;
-1
View File
@@ -1958,7 +1958,6 @@ func downloadDockerImageBackend(client *http.Client, imageName string) error {
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", authorization)) req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", authorization))
} else { } else {
log.Printf("[WARNING] No auth found - running backend download without it.") log.Printf("[WARNING] No auth found - running backend download without it.")
//req.Header.Add("Authorization", fmt.Sprintf("Bearer db0373c6-1083-4dec-a05d-3ba73f02ccd4"))
//return //return
} }