diff --git a/demos/jans-tarp/package.json b/demos/jans-tarp/package.json
index da670f216a2..f12daf3101b 100644
--- a/demos/jans-tarp/package.json
+++ b/demos/jans-tarp/package.json
@@ -32,13 +32,16 @@
"adm-zip": "^0.5.10",
"autoprefixer": "^10.4.7",
"axios": "^1.4.0",
+ "jwt-decode": "^4.0.0",
"moment": "^2.29.4",
"postcss": "^8.4.14",
"qs": "^6.11.2",
"react-datepicker": "^4.12.0",
+ "react-dropzone": "^14.2.3",
"react-router-dom": "6.2",
"react-select": "^5.7.3",
"react-spinner-overlay": "^0.1.33",
+ "styled-components": "^6.1.0",
"uuid": "^9.0.0"
}
}
diff --git a/demos/jans-tarp/src/options/StyledDropzone.tsx b/demos/jans-tarp/src/options/StyledDropzone.tsx
new file mode 100644
index 00000000000..03f586d62b2
--- /dev/null
+++ b/demos/jans-tarp/src/options/StyledDropzone.tsx
@@ -0,0 +1,77 @@
+import React, { useEffect, useCallback, useState } from 'react';
+import { useDropzone } from 'react-dropzone';
+import styled from 'styled-components';
+
+const getColor = (props) => {
+ if (props.isDragAccept) {
+ return '#00e676';
+ }
+ if (props.isDragReject) {
+ return '#ff1744';
+ }
+ if (props.isFocused) {
+ return '#2196f3';
+ }
+ return '#eeeeee';
+}
+
+const Container = styled.div`
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 20px;
+ border-width: 2px;
+ border-radius: 2px;
+ border-color: ${props => getColor(props)};
+ border-style: dashed;
+ background-color: #fafafa;
+ color: #bdbdbd;
+ outline: none;
+ transition: border .24s ease-in-out;
+ margin-bottom: 30px;
+`;
+
+function StyledDropzone(props) {
+
+ const [selectedFileName, setSelectedFileName] = useState(null)
+ const [selectedFile, setSelectedFile] = useState(null)
+
+ useEffect(() => {
+ if (selectedFile) {
+ props.submitFile(selectedFile)
+ }
+ }, [selectedFile])
+
+ const onDrop = useCallback(acceptedFiles => {
+ const file = acceptedFiles[0]
+ setSelectedFileName(file.name)
+ setSelectedFile(file)
+ }, [])
+ const { getRootProps,
+ getInputProps,
+ isFocused,
+ isDragAccept,
+ isDragReject } = useDropzone({
+ onDrop,
+ accept: {
+ 'application/jwt': ['.jwt'],
+ },
+ })
+
+
+ return (
+
+
+
+ {selectedFileName ? (
+ Selected File : {selectedFileName}
+ ) : (
+ Drag 'n' drop .jwt file here, or click to select file
+ )}
+
+
+ );
+}
+
+export default StyledDropzone;
\ No newline at end of file
diff --git a/demos/jans-tarp/src/options/options.css b/demos/jans-tarp/src/options/options.css
index 16e5d49877a..62363440e42 100644
--- a/demos/jans-tarp/src/options/options.css
+++ b/demos/jans-tarp/src/options/options.css
@@ -95,7 +95,7 @@ fieldset {
legend {
font-size: 1.4em;
- margin-bottom: 10px;
+ margin-bottom: 20px;
}
label {
@@ -142,7 +142,7 @@ label.light {
display: flex;
flex-direction: column;
justify-content: center;
- align-items: center;
+ align-items: left;
min-width: 600px;
font-size: 15px;
padding: 2rem;
diff --git a/demos/jans-tarp/src/options/registerForm.tsx b/demos/jans-tarp/src/options/registerForm.tsx
index b41df3f6d88..d743f15d501 100644
--- a/demos/jans-tarp/src/options/registerForm.tsx
+++ b/demos/jans-tarp/src/options/registerForm.tsx
@@ -1,4 +1,4 @@
-import React, { useState, KeyboardEventHandler } from 'react'
+import React, { useState, KeyboardEventHandler, useCallback, useEffect } from 'react'
import axios from 'axios';
import './options.css'
import { v4 as uuidv4 } from 'uuid';
@@ -9,6 +9,8 @@ import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
import moment from 'moment';
import { ILooseObject } from './ILooseObject';
+import StyledDropzone from './StyledDropzone';
+import { jwtDecode } from "jwt-decode";
const components = {
DropdownIndicator: null,
};
@@ -24,10 +26,178 @@ const RegisterForm = (data) => {
const [inputValueIssuer, setInputValueIssuer] = useState('');
const [inputValueScope, setInputValueScope] = useState('');
const [isLoading, setIsLoading] = useState(false);
+ const [uploadSsa, setUploadSsa] = useState(false);
const [showClientExpiry, setShowClientExpiry] = useState(false);
const [issuerOption, setIssuerOption] = useState([]);
const [scopeOption, setScopeOption] = useState([createOption('openid')]);
const [clientExpiryDate, setClientExpiryDate] = useState(moment().add(1, 'days').toDate());
+ const [ssaJwt, setSsaJwt] = useState(null)
+ const REGISTRATION_ERROR = 'Error in registration. Check web console for logs.'
+
+ const readJWTFile = (selectedFile) => {
+ const reader = new FileReader()
+
+ reader.onload = () => {
+ const token = reader.result
+ setSsaJwt(token)
+ }
+
+ const blob = new Blob([selectedFile])
+ reader.readAsText(blob)
+ }
+
+ async function triggerClientRegistration() {
+ try {
+ if (uploadSsa) {
+ const response = await processForClientRegiWithSSA()
+ if (response.result !== 'success') {
+ setError(REGISTRATION_ERROR);
+ }
+ setPageLoading(false);
+ } else if (validate()) {
+
+ setPageLoading(true);
+ const response = await processForClientRegiWithoutSSA()
+ if (response.result !== 'success') {
+ setError(REGISTRATION_ERROR);
+ }
+ setPageLoading(false);
+ }
+ } catch (err) {
+ console.error(err)
+ }
+ }
+
+ async function processForClientRegiWithSSA() {
+ try {
+ const ssaJson = jwtDecode(ssaJwt)
+ if (ssaJson.iss == null) {
+ setError('Issuer not found in SSA.')
+ }
+
+ const issuer = ssaJson.iss
+
+ const configurationUrl = generateOpenIdConfigurationURL(issuer)
+ const openapiConfig = await getOpenidConfiguration(configurationUrl)
+
+ if (openapiConfig != undefined) {
+ chrome.storage.local.set({ opConfiguration: openapiConfig.data }).then(() => {
+ console.log("openapiConfig is set to " + openapiConfig);
+ });
+
+ const registrationUrl = openapiConfig.data.registration_endpoint;
+
+ var registerObj: ILooseObject = {
+ redirect_uris: [issuer],
+ software_statement: ssaJwt,
+ response_types: ['code'],
+ grant_types: ['authorization_code'],
+ application_type: 'web',
+ client_name: 'jans-tarp-' + uuidv4(),
+ token_endpoint_auth_method: 'client_secret_basic',
+ post_logout_redirect_uris: [chrome.runtime.getURL('options.html')]
+ }
+
+ const registrationResp = await registerOIDCClient(registrationUrl, registerObj)
+
+ if (registrationResp !== undefined) {
+ chrome.storage.local.set({
+ oidcClient: {
+ 'op_host': issuer,
+ 'client_id': registrationResp.data.client_id,
+ 'client_secret': registrationResp.data.client_secret,
+ 'scope': registerObj.scope,
+ 'redirect_uri': registerObj.redirect_uris,
+ 'authorization_endpoint': openapiConfig.data.authorization_endpoint,
+ 'response_type': registerObj.response_types,
+ 'post_logout_redirect_uris': registerObj.post_logout_redirect_uris,
+ 'expire_at': clientExpiryDate.getTime(),
+ 'showClientExpiry': showClientExpiry
+
+ }
+ })
+ console.log('OIDC client registered successfully!')
+ console.log("oidcClient is set for client_id: " + registrationResp.data.client_id)
+
+ return await { result: "success", message: "Regstration successful!" }
+
+ } else {
+ return await { result: "error", message: REGISTRATION_ERROR }
+ }
+ } else {
+ return await { result: "error", message: "Error in fetching Openid configuration!" }
+ }
+ } catch (err) {
+ console.error(err)
+ return { result: "error", message: REGISTRATION_ERROR + err.message }
+ }
+ }
+
+ async function processForClientRegiWithoutSSA() {
+ try {
+ const opConfigurationEndpoint = generateOpenIdConfigurationURL(issuerOption.map((iss) => iss.value)[0]);
+ const opConfigurationEndpointURL = new URL(opConfigurationEndpoint);
+ const issuer = opConfigurationEndpointURL.protocol + '//' + opConfigurationEndpointURL.hostname;
+ const scope = scopeOption.map((ele) => ele.value).join(" ");
+
+ const openapiConfig = await getOpenidConfiguration(opConfigurationEndpoint);
+
+ if (openapiConfig != undefined) {
+ chrome.storage.local.set({ opConfiguration: openapiConfig.data }).then(() => {
+ console.log("openapiConfig is set to " + openapiConfig);
+ });
+
+ const registrationUrl = openapiConfig.data.registration_endpoint;
+
+ var registerObj: ILooseObject = {
+ redirect_uris: [issuer],
+ scope: scope,
+ post_logout_redirect_uris: [chrome.runtime.getURL('options.html')],
+ response_types: ['code'],
+ grant_types: ['authorization_code'],
+ application_type: 'web',
+ client_name: 'jans-tarp-' + uuidv4(),
+ token_endpoint_auth_method: 'client_secret_basic'
+ };
+
+ if (showClientExpiry) {
+ registerObj.lifetime = ((clientExpiryDate.getTime() - moment().toDate().getTime()) / 1000);
+ }
+
+ const registrationResp = await registerOIDCClient(registrationUrl, registerObj);
+
+ if (registrationResp !== undefined) {
+ chrome.storage.local.set({
+ oidcClient: {
+ 'op_host': issuer,
+ 'client_id': registrationResp.data.client_id,
+ 'client_secret': registrationResp.data.client_secret,
+ 'scope': registerObj.scope,
+ 'redirect_uri': registerObj.redirect_uris,
+ 'authorization_endpoint': openapiConfig.data.authorization_endpoint,
+ 'response_type': registerObj.response_types,
+ 'post_logout_redirect_uris': registerObj.post_logout_redirect_uris,
+ 'expire_at': clientExpiryDate.getTime(),
+ 'showClientExpiry': showClientExpiry
+
+ }
+ })
+ console.log('OIDC client registered successfully!')
+ console.log("oidcClient is set for client_id: " + registrationResp.data.client_id);
+
+ return await { result: "success", message: "Regstration successful!" };
+
+ } else {
+ return await { result: "error", message: REGISTRATION_ERROR };
+ }
+ } else {
+ return await { result: "error", message: "Error in fetching Openid configuration!" };
+ }
+ } catch (err) {
+ console.error(err)
+ return { result: "error", message: REGISTRATION_ERROR };
+ }
+ }
const handleKeyDown: KeyboardEventHandler = async (event) => {
const inputId = (event.target as HTMLInputElement).id;
@@ -114,86 +284,6 @@ const RegisterForm = (data) => {
return true;
}
- async function registerClient() {
- if (validate()) {
- try {
- setPageLoading(true);
- const response = await register()
- if (response.result !== 'success') {
- setError('Error in registration.');
- }
- setPageLoading(false);
- } catch (err) {
- console.error(err)
- }
- }
- }
-
- async function register() {
- try {
- const opConfigurationEndpoint = generateOpenIdConfigurationURL(issuerOption.map((iss) => iss.value)[0]);
- const opConfigurationEndpointURL = new URL(opConfigurationEndpoint);
- const issuer = opConfigurationEndpointURL.protocol + '//' + opConfigurationEndpointURL.hostname;
- const scope = scopeOption.map((ele) => ele.value).join(" ");
- const openapiConfig = await getOpenidConfiguration(opConfigurationEndpoint);
-
- if (openapiConfig != undefined) {
- chrome.storage.local.set({ opConfiguration: openapiConfig.data }).then(() => {
- console.log("openapiConfig is set to " + openapiConfig);
- });
-
- const registrationUrl = openapiConfig.data.registration_endpoint;
-
- var registerObj: ILooseObject = {
- redirect_uris: [issuer],
- scope: scope,
- post_logout_redirect_uris: [chrome.runtime.getURL('options.html')],
- response_types: ['code'],
- grant_types: ['authorization_code', 'client_credentials'],
- application_type: 'web',
- client_name: 'Gluu-RP-' + uuidv4(),
- token_endpoint_auth_method: 'client_secret_basic'
- };
-
- if (showClientExpiry) {
- registerObj.lifetime = ((clientExpiryDate.getTime() - moment().toDate().getTime()) / 1000);
- }
-
- const registrationResp = await registerOIDCClient(registrationUrl, registerObj);
-
- if (registrationResp !== undefined) {
- chrome.storage.local.set({
- oidcClient: {
- 'op_host': issuer,
- 'client_id': registrationResp.data.client_id,
- 'client_secret': registrationResp.data.client_secret,
- 'scope': registerObj.scope,
- 'redirect_uri': registerObj.redirect_uris,
- 'authorization_endpoint': openapiConfig.data.authorization_endpoint,
- 'response_type': registerObj.response_types,
- 'post_logout_redirect_uris': registerObj.post_logout_redirect_uris,
- 'expire_at': clientExpiryDate.getTime(),
- 'showClientExpiry': showClientExpiry
-
- }
- })
- console.log('OIDC client registered successfully!')
- console.log("oidcClient is set for client_id: " + registrationResp.data.client_id);
-
- return await { result: "success", message: "Regstration successful!" };
-
- } else {
- return await { result: "error", message: "Error in registration!" };
- }
- } else {
- return await { result: "error", message: "Error in fetching Openid configuration!" };
- }
- } catch (err) {
- console.error(err)
- return { result: "error", message: "Error in registration!" };
- }
- }
-
async function registerOIDCClient(registration_endpoint, registerObj) {
try {
const registerReqOptions = {
@@ -223,60 +313,75 @@ const RegisterForm = (data) => {
}
}
+ function handleChange(event) {
+ setSsaJwt(event.target.value)
+ }
+
return (
{error.length > 0 ? : ""}
-
- setIssuerOption(newValue)}
- onInputChange={(newValue) => setInputValueIssuer(newValue)}
- onKeyDown={handleKeyDown}
- placeholder="Type something and press enter..."
- value={issuerOption}
- className="inputText"
- />
-
-
- {showClientExpiry ?
+
+ {uploadSsa ?
<>
-
- setClientExpiryDate(date)}
- minDate={new Date()}
- className="inputText inputStyle"
- dateFormat="yyyy/MM/dd h:mm aa"
+
+
+
+ >
+ :
+ <>
+
+ setIssuerOption(newValue)}
+ onInputChange={(newValue) => setInputValueIssuer(newValue)}
+ onKeyDown={handleKeyDown}
+ placeholder="Type something and press enter..."
+ value={issuerOption}
+ className="inputText"
+ />
+
+
+ {showClientExpiry ?
+ <>
+
+ setClientExpiryDate(date)}
+ minDate={new Date()}
+ className="inputText inputStyle"
+ dateFormat="yyyy/MM/dd h:mm aa"
+ />
+ > : ''}
+
+
+ setScopeOption(newValue)}
+ onInputChange={(newValue) => setInputValueScope(newValue)}
+ onKeyDown={handleKeyDown}
+ placeholder="Type something and press enter..."
+ value={scopeOption}
+ className="inputText"
/>
- > : ''}
-
-
- setScopeOption(newValue)}
- onInputChange={(newValue) => setInputValueScope(newValue)}
- onKeyDown={handleKeyDown}
- placeholder="Type something and press enter..."
- value={scopeOption}
- className="inputText"
- />
-
-
-
+
+
+ >
+ }
+
)
};