Merge pull request #2624 from BobcatProgrammer/feat-926-oauth2-microsoft-tenant-config
feat: Make OAuth2 Microsoft Provider configureable
This commit is contained in:
commit
4544483539
13 changed files with 1149 additions and 1002 deletions
|
@ -127,7 +127,7 @@ return [ // Ordered by ABC.
|
|||
'icon' => 'icon-windows',
|
||||
'enabled' => true,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'form' => 'microsoft.phtml',
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
|
|
|
@ -315,7 +315,7 @@ App::get('/v1/account/sessions/oauth2/callback/:provider/:projectId')
|
|||
->label('docs', false)
|
||||
->param('projectId', '', new Text(1024), 'Project ID.')
|
||||
->param('provider', '', new WhiteList(\array_keys(Config::getParam('providers')), true), 'OAuth2 provider.')
|
||||
->param('code', '', new Text(1024), 'OAuth2 code.')
|
||||
->param('code', '', new Text(2048), 'OAuth2 code.')
|
||||
->param('state', '', new Text(2048), 'Login state params.', true)
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
|
@ -342,7 +342,7 @@ App::post('/v1/account/sessions/oauth2/callback/:provider/:projectId')
|
|||
->label('docs', false)
|
||||
->param('projectId', '', new Text(1024), 'Project ID.')
|
||||
->param('provider', '', new WhiteList(\array_keys(Config::getParam('providers')), true), 'OAuth2 provider.')
|
||||
->param('code', '', new Text(1024), 'OAuth2 code.')
|
||||
->param('code', '', new Text(2048), 'OAuth2 code.')
|
||||
->param('state', '', new Text(2048), 'Login state params.', true)
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
|
@ -370,7 +370,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
|||
->label('abuse-key', 'ip:{ip}')
|
||||
->label('docs', false)
|
||||
->param('provider', '', new WhiteList(\array_keys(Config::getParam('providers')), true), 'OAuth2 provider.')
|
||||
->param('code', '', new Text(1024), 'OAuth2 code.')
|
||||
->param('code', '', new Text(2048), 'OAuth2 code.')
|
||||
->param('state', '', new Text(2048), 'OAuth2 state params.', true)
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<?php
|
||||
use Appwrite\Utopia\View;
|
||||
|
||||
$providers = $this->getParam('providers', []);
|
||||
$auth = $this->getParam('auth', []);
|
||||
$smtpEnabled = $this->getParam('smtpEnabled', false);
|
||||
|
@ -475,9 +477,12 @@ $smtpEnabled = $this->getParam('smtpEnabled', false);
|
|||
<label for="oauth2<?php echo $this->escape(ucfirst($provider)); ?>Secret">App Secret</label>
|
||||
<input name="secret" data-forms-show-secret id="oauth2<?php echo $this->escape(ucfirst($provider)); ?>Secret" type="password" autocomplete="off" data-ls-bind="{{console-project.provider<?php echo $this->escape(ucfirst($provider)); ?>Secret}}">
|
||||
<?php else: ?>
|
||||
<label for="oauth2<?php echo $this->escape(ucfirst($provider)); ?>Appid">Bundle ID <span class="tooltip" data-tooltip="Attribute internal display name"><i class="icon-info-circled"></i></span></label>
|
||||
<input name="appId" id="oauth2<?php echo $this->escape(ucfirst($provider)); ?>Appid" type="text" autocomplete="off" data-ls-bind="{{console-project.provider<?php echo $this->escape(ucfirst($provider)); ?>Appid}}" placeholder="com.company.appname" />
|
||||
<input name="secret" data-forms-oauth-apple id="oauth2<?php echo $this->escape(ucfirst($provider)); ?>Secret" type="hidden" autocomplete="off" data-ls-bind="{{console-project.provider<?php echo $this->escape(ucfirst($provider)); ?>Secret}}" />
|
||||
<?php
|
||||
$form = new View(__DIR__.'/oauth/'.$this->escape($form));
|
||||
echo $form
|
||||
->setParam("provider", $provider)
|
||||
->render();
|
||||
?>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="info row thin margin-bottom margin-top">
|
||||
|
|
13
app/views/console/users/oauth/apple.phtml
Normal file
13
app/views/console/users/oauth/apple.phtml
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
$provider = $this->getParam('provider', '');
|
||||
?>
|
||||
|
||||
<label for="oauth2<?php echo $this->escape(ucfirst($provider)); ?>Appid">Bundle ID <span class="tooltip" data-tooltip="Attribute internal display name"><i class="icon-info-circled"></i></span></label>
|
||||
<input name="appId" id="oauth2<?php echo $this->escape(ucfirst($provider)); ?>Appid" type="text" autocomplete="off" data-ls-bind="{{console-project.provider<?php echo $this->escape(ucfirst($provider)); ?>Appid}}" placeholder="com.company.appname" />
|
||||
<input name="secret" data-forms-oauth-custom="<?php echo $this->escape(ucfirst($provider)); ?>" id="oauth2<?php echo $this->escape(ucfirst($provider)); ?>Secret" type="hidden" autocomplete="off" data-ls-bind="{{console-project.provider<?php echo $this->escape(ucfirst($provider)); ?>Secret}}" />
|
||||
<div>
|
||||
<div class="row thin">
|
||||
<div class="col span-6"><label>Key ID</label><input id="oauth2AppleKeyId" type="text" placeholder="SHAB13ROFN"></div>
|
||||
<div class="col span-6"><label>Team ID</label><input id="oauth2AppleTeamId" type="text" placeholder="ELA2CD3AED"></div>
|
||||
</div><label>P8 File</label><textarea id="oauth2AppleP8" class="margin-bottom-no"></textarea>
|
||||
</div>
|
12
app/views/console/users/oauth/microsoft.phtml
Normal file
12
app/views/console/users/oauth/microsoft.phtml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
$provider = $this->getParam('provider', '');
|
||||
?>
|
||||
|
||||
<label for="oauth2<?php echo $this->escape(ucfirst($provider)); ?>Appid">Application (Client) ID<span class="tooltip" data-tooltip="Provided by AzureAD"><i class="icon-info-circled"></i></span></label>
|
||||
<input name="appId" id="oauth2<?php echo $this->escape(ucfirst($provider)); ?>Appid" type="text" autocomplete="off" data-ls-bind="{{console-project.provider<?php echo $this->escape(ucfirst($provider)); ?>Appid}}" placeholder="Application ID" />
|
||||
<label for="oauth2<?php echo $this->escape(ucfirst($provider)); ?>ClientSecret">Client Secret <span class="tooltip" data-tooltip="Created by you in AzureAD Portal"><i class="icon-info-circled"></i></span></label>
|
||||
<input name="appSecret" id="oauth2<?php echo $this->escape(ucfirst($provider)); ?>ClientSecret" type="password" autocomplete="off" placeholder="Client Secret" />
|
||||
<label for="oauth2<?php echo $this->escape(ucfirst($provider)); ?>TenantId">Target Tenant<span class="tooltip" data-tooltip="'common', 'organizations', 'consumers' or your TenantId"><i class="icon-info-circled"></i></span><a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-protocols#endpoints">More info</a></label>
|
||||
<input name="appSecret" id="oauth2<?php echo $this->escape(ucfirst($provider)); ?>TenantId" type="text" autocomplete="off" placeholder="'common', 'organizations', 'consumers' or your TenantId" />
|
||||
<?php /*Hidden input for the final secret. Gets filled with a JSON via JS. */ ?>
|
||||
<input name="secret" data-forms-oauth-custom="<?php echo $this->escape(ucfirst($provider)); ?>" id="oauth2<?php echo $this->escape(ucfirst($provider)); ?>Secret" type="hidden" autocomplete="off" data-ls-bind="{{console-project.provider<?php echo $this->escape(ucfirst($provider)); ?>Secret}}" />
|
|
@ -175,4 +175,34 @@ If everything goes well, raise a pull request and be ready to respond to any fee
|
|||
First of all, commit the changes with the message `Added XXX OAuth2 Provider` and push it. This will publish a new branch to your forked version of Appwrite. If you visit it at `github.com/YOUR_USERNAME/appwrite`, you will see a new alert saying you are ready to submit a pull request. Follow the steps GitHub provides, and at the end, you will have your pull request submitted.
|
||||
|
||||
## 🤕 Stuck ?
|
||||
|
||||
If you need any help with the contribution, feel free to head over to [our discord channel](https://appwrite.io/discord) and we'll be happy to help you out.
|
||||
|
||||
## 😉 Need more freedom
|
||||
|
||||
If your OAuth provider requires special configuration apart from `clientId` and `clientSecret` you can create a custom form. Currently this is being realized through putting all custom fields as JSON into the `clientSecret` field to keep the project API stable. You can implement your custom form following these steps:
|
||||
|
||||
1. Add your custom form in `app/views/console/users/oauth/[PROVIDER].phtml`. Below is a template you can use. Add the filename to `app/config/providers.php`.
|
||||
|
||||
```php
|
||||
<?php
|
||||
$provider = $this->getParam('provider', '');
|
||||
?>
|
||||
<label for="oauth2<?php echo $this->escape(ucfirst($provider)); ?>Appid">Application (Client) ID<span class="tooltip" data-tooltip="Provided by AzureAD"><i class="icon-info-circled"></i></span></label>
|
||||
<input name="appId" id="oauth2<?php echo $this->escape(ucfirst($provider)); ?>Appid" type="text" autocomplete="off" data-ls-bind="{{console-project.provider<?php echo $this->escape(ucfirst($provider)); ?>Appid}}" placeholder="Application ID" />
|
||||
<?php /*Hidden input for the final secret. Gets filled with a JSON via JS. */ ?>
|
||||
<input name="secret" data-forms-oauth-custom="<?php echo $this->escape(ucfirst($provider)); ?>" id="oauth2<?php echo $this->escape(ucfirst($provider)); ?>Secret" type="hidden" autocomplete="off" data-ls-bind="{{console-project.provider<?php echo $this->escape(ucfirst($provider)); ?>Secret}}" />
|
||||
<!-- [Your custom form inputs go here] -->
|
||||
```
|
||||
|
||||
2. Add the config for creating the JSON in `public/scripts/views/forms/oauth-custom.js` using this template
|
||||
```js
|
||||
{
|
||||
"[Provider]":{
|
||||
"[JSON property name 1]":"[html element Id 1]",
|
||||
"[JSON property name 2]":"[html element Id 2]"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. In your provider class `src/Appwrite/Auth/OAuth2/[Provider].php` add logic to decode the JSON using the same property names.
|
||||
|
|
|
@ -57,7 +57,7 @@ const configApp = {
|
|||
'public/scripts/views/forms/move-down.js',
|
||||
'public/scripts/views/forms/move-up.js',
|
||||
'public/scripts/views/forms/nav.js',
|
||||
'public/scripts/views/forms/oauth-apple.js',
|
||||
'public/scripts/views/forms/oauth-custom.js',
|
||||
'public/scripts/views/forms/password-meter.js',
|
||||
'public/scripts/views/forms/pell.js',
|
||||
'public/scripts/views/forms/required.js',
|
||||
|
|
934
public/dist/scripts/app-all.js
vendored
934
public/dist/scripts/app-all.js
vendored
File diff suppressed because it is too large
Load diff
926
public/dist/scripts/app-dep.js
vendored
926
public/dist/scripts/app-dep.js
vendored
File diff suppressed because it is too large
Load diff
8
public/dist/scripts/app.js
vendored
8
public/dist/scripts/app.js
vendored
|
@ -778,10 +778,14 @@ list["filters-"+filter.key]=params[key][i];}}}}
|
|||
return list;};let apply=function(params){let cached=container.get(name);cached=cached?cached.params:[];params=Object.assign(cached,params);container.set(name,{name:name,params:params,query:serialize(params),forward:parseInt(params.offset)+parseInt(params.limit),backward:parseInt(params.offset)-parseInt(params.limit),keys:flatten(params)},true,name);document.dispatchEvent(new CustomEvent(name+"-changed",{bubbles:false,cancelable:true}));};switch(element.tagName){case"INPUT":break;case"TEXTAREA":break;case"BUTTON":element.addEventListener("click",function(){apply(JSON.parse(expression.parse(element.dataset["params"]||"{}")));});break;case"FORM":element.addEventListener("input",function(){apply(form.toJson(element));});element.addEventListener("change",function(){apply(form.toJson(element));});element.addEventListener("reset",function(){setTimeout(function(){apply(form.toJson(element));},0);});events=events.trim().split(",");for(let y=0;y<events.length;y++){if(events[y]==="init"){element.addEventListener("rendered",function(){apply(form.toJson(element));},{once:true});}else{}
|
||||
element.setAttribute("data-event","none");}
|
||||
break;default:break;}}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-forms-headers",controller:function(element){let key=document.createElement("input");let value=document.createElement("input");let wrap=document.createElement("div");let cell1=document.createElement("div");let cell2=document.createElement("div");key.type="text";key.className="margin-bottom-no";key.placeholder="Key";value.type="text";value.className="margin-bottom-no";value.placeholder="Value";wrap.className="row thin margin-bottom-small";cell1.className="col span-6";cell2.className="col span-6";element.parentNode.insertBefore(wrap,element);cell1.appendChild(key);cell2.appendChild(value);wrap.appendChild(cell1);wrap.appendChild(cell2);key.addEventListener("input",function(){syncA();});value.addEventListener("input",function(){syncA();});element.addEventListener("change",function(){syncB();});let syncA=function(){element.value=key.value.toLowerCase()+":"+value.value.toLowerCase();};let syncB=function(){let split=element.value.toLowerCase().split(":");key.value=split[0]||"";value.value=split[1]||"";key.value=key.value.trim();value.value=value.value.trim();};syncB();}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-forms-key-value",controller:function(element){let key=document.createElement("input");let value=document.createElement("input");let wrap=document.createElement("div");let cell1=document.createElement("div");let cell2=document.createElement("div");key.type="text";key.className="margin-bottom-no";key.placeholder="Key";key.required=true;value.type="text";value.className="margin-bottom-no";value.placeholder="Value";value.required=true;wrap.className="row thin margin-bottom-small";cell1.className="col span-6";cell2.className="col span-6";element.parentNode.insertBefore(wrap,element);cell1.appendChild(key);cell2.appendChild(value);wrap.appendChild(cell1);wrap.appendChild(cell2);key.addEventListener("input",function(){syncA();});value.addEventListener("input",function(){syncA();});element.addEventListener("change",function(){syncB();});let syncA=function(){element.name=key.value;element.value=value.value;};let syncB=function(){key.value=element.name||"";value.value=element.value||"";};syncB();}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-move-down",controller:function(element){Array.prototype.slice.call(element.querySelectorAll("[data-move-down]")).map(function(obj){obj.addEventListener("click",function(){if(element.nextElementSibling){console.log('down',element.offsetHeight);element.parentNode.insertBefore(element.nextElementSibling,element);element.scrollIntoView({block:'center'});}});});}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-move-up",controller:function(element){Array.prototype.slice.call(element.querySelectorAll("[data-move-up]")).map(function(obj){obj.addEventListener("click",function(){if(element.previousElementSibling){console.log('up',element);element.parentNode.insertBefore(element,element.previousElementSibling);element.scrollIntoView({block:'center'});}});});}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-nav",repeat:false,controller:function(element,view,container,document){let titles=document.querySelectorAll('[data-forms-nav-anchor]');let links=element.querySelectorAll('[data-forms-nav-link]');let minLink=null;let check=function(){let minDistance=null;let minElement=null;for(let i=0;i<titles.length;++i){let title=titles[i];let distance=title.getBoundingClientRect().top;console.log(i);if((minDistance===null||minDistance>=distance)&&(distance>=0)){if(minLink){minLink.classList.remove('selected');}
|
||||
console.log('old',minLink);minDistance=distance;minElement=title;minLink=links[i];minLink.classList.add('selected');console.log('new',minLink);}}};window.addEventListener('scroll',check);check();}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-oauth-apple",controller:function(element){let container=document.createElement("div");let row=document.createElement("div");let col1=document.createElement("div");let col2=document.createElement("div");let keyID=document.createElement("input");let keyLabel=document.createElement("label");let teamID=document.createElement("input");let teamLabel=document.createElement("label");let p8=document.createElement("textarea");let p8Label=document.createElement("label");keyLabel.textContent='Key ID';teamLabel.textContent='Team ID';p8Label.textContent='P8 File';row.classList.add('row');row.classList.add('thin');container.appendChild(row);container.appendChild(p8Label);container.appendChild(p8);row.appendChild(col1);row.appendChild(col2);col1.classList.add('col');col1.classList.add('span-6');col1.appendChild(keyLabel);col1.appendChild(keyID);col2.classList.add('col');col2.classList.add('span-6');col2.appendChild(teamLabel);col2.appendChild(teamID);keyID.type='text';keyID.placeholder='SHAB13ROFN';teamID.type='text';teamID.placeholder='ELA2CD3AED';p8.accept='.p8';p8.classList.add('margin-bottom-no');element.parentNode.insertBefore(container,element.nextSibling);element.addEventListener('change',sync);keyID.addEventListener('change',update);teamID.addEventListener('change',update);p8.addEventListener('change',update);function update(){let json={};json.keyID=keyID.value;json.teamID=teamID.value;json.p8=p8.value;element.value=JSON.stringify(json);}
|
||||
console.log('old',minLink);minDistance=distance;minElement=title;minLink=links[i];minLink.classList.add('selected');console.log('new',minLink);}}};window.addEventListener('scroll',check);check();}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-oauth-custom",controller:function(element){let providers={"Microsoft":{"clientSecret":"oauth2MicrosoftClientSecret","tenantId":"oauth2MicrosoftTenantId"},"Apple":{"keyId":"oauth2AppleKeyId","teamId":"oauth2AppleTeamId","p8":"oauth2AppleP8"}}
|
||||
let provider=element.getAttribute("data-forms-oauth-custom");if(!provider||!providers.hasOwnProperty(provider)){console.error("Provider for custom form not set or unkown")}
|
||||
let config=providers[provider];element.addEventListener('change',sync);let elements={};for(const key in config){if(Object.hasOwnProperty.call(config,key)){elements[key]=document.getElementById(config[key]);elements[key].addEventListener('change',update);}}
|
||||
function update(){let json={};for(const key in elements){if(Object.hasOwnProperty.call(elements,key)){json[key]=elements[key].value}}
|
||||
element.value=JSON.stringify(json);}
|
||||
function sync(){if(!element.value){return;}
|
||||
let json={};try{json=JSON.parse(element.value);}catch(error){console.error('Failed to parse secret key');}
|
||||
teamID.value=json.teamID||'';keyID.value=json.keyID||'';p8.value=json.p8||'';}
|
||||
for(const key in elements){if(Object.hasOwnProperty.call(elements,key)){elements[key].value=json[key]||'';}}}
|
||||
sync();}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-password-meter",controller:function(element,window){var calc=function(password){var score=0;if(!password)return score;var letters=new window.Object();for(var i=0;i<password.length;i++){letters[password[i]]=(letters[password[i]]||0)+1;score+=5.0/letters[password[i]];}
|
||||
var variations={digits:/\d/.test(password),lower:/[a-z]/.test(password),upper:/[A-Z]/.test(password),nonWords:/\W/.test(password)};var variationCount=0;for(var check in variations){if(variations.hasOwnProperty(check)){variationCount+=variations[check]===true?1:0;}}
|
||||
score+=(variationCount-1)*10;return parseInt(score);};var callback=function(){var score=calc(this.value);if(""===this.value)return(meter.className="password-meter");if(score>60)return(meter.className="password-meter strong");if(score>30)return(meter.className="password-meter medium");if(score>=0)return(meter.className="password-meter weak");};var meter=window.document.createElement("div");meter.className="password-meter";element.parentNode.insertBefore(meter,element.nextSibling);element.addEventListener("change",callback);element.addEventListener("keypress",callback);element.addEventListener("keyup",callback);element.addEventListener("keydown",callback);}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-pell",controller:function(element,window,document,markdown,rtl){var div=document.createElement("div");element.className="pell hide";div.className="input pell";element.parentNode.insertBefore(div,element);element.tabIndex=-1;var turndownService=new TurndownService();turndownService.addRule("underline",{filter:["u"],replacement:function(content){return"__"+content+"__";}});var editor=window.pell.init({element:div,onChange:function onChange(html){alignText();element.value=turndownService.turndown(html);},defaultParagraphSeparator:"p",actions:[{name:"bold",icon:'<i class="icon-bold"></i>'},{name:"underline",icon:'<i class="icon-underline"></i>'},{name:"italic",icon:'<i class="icon-italic"></i>'},{name:"olist",icon:'<i class="icon-list-numbered"></i>'},{name:"ulist",icon:'<i class="icon-list-bullet"></i>'},{name:"link",icon:'<i class="icon-link"></i>'}]});var clean=function(e){e.stopPropagation();e.preventDefault();var clipboardData=e.clipboardData||window.clipboardData;console.log(clipboardData.getData("Text"));window.pell.exec("insertText",clipboardData.getData("Text"));return true;};var alignText=function(){let paragraphs=editor.content.querySelectorAll('p,li');let last='';for(let paragraph of paragraphs){var content=paragraph.textContent;if(content.trim()===''){content=last.textContent;}
|
||||
|
|
|
@ -1,93 +0,0 @@
|
|||
(function(window) {
|
||||
"use strict";
|
||||
|
||||
window.ls.container.get("view").add({
|
||||
selector: "data-forms-oauth-apple",
|
||||
controller: function(element) {
|
||||
let container = document.createElement("div");
|
||||
let row = document.createElement("div");
|
||||
let col1 = document.createElement("div");
|
||||
let col2 = document.createElement("div");
|
||||
let keyID = document.createElement("input");
|
||||
let keyLabel = document.createElement("label");
|
||||
let teamID = document.createElement("input");
|
||||
let teamLabel = document.createElement("label");
|
||||
let p8 = document.createElement("textarea");
|
||||
let p8Label = document.createElement("label");
|
||||
|
||||
keyLabel.textContent = 'Key ID';
|
||||
teamLabel.textContent = 'Team ID';
|
||||
p8Label.textContent = 'P8 File';
|
||||
|
||||
row.classList.add('row');
|
||||
row.classList.add('thin');
|
||||
container.appendChild(row);
|
||||
container.appendChild(p8Label);
|
||||
container.appendChild(p8);
|
||||
|
||||
row.appendChild(col1);
|
||||
row.appendChild(col2);
|
||||
|
||||
col1.classList.add('col');
|
||||
col1.classList.add('span-6');
|
||||
col1.appendChild(keyLabel);
|
||||
col1.appendChild(keyID);
|
||||
|
||||
col2.classList.add('col');
|
||||
col2.classList.add('span-6');
|
||||
col2.appendChild(teamLabel);
|
||||
col2.appendChild(teamID);
|
||||
|
||||
keyID.type = 'text';
|
||||
keyID.placeholder = 'SHAB13ROFN';
|
||||
teamID.type = 'text';
|
||||
teamID.placeholder = 'ELA2CD3AED';
|
||||
p8.accept = '.p8';
|
||||
p8.classList.add('margin-bottom-no');
|
||||
|
||||
element.parentNode.insertBefore(container, element.nextSibling);
|
||||
|
||||
element.addEventListener('change', sync);
|
||||
keyID.addEventListener('change', update);
|
||||
teamID.addEventListener('change', update);
|
||||
p8.addEventListener('change', update);
|
||||
|
||||
function update() {
|
||||
let json = {};
|
||||
|
||||
json.keyID = keyID.value;
|
||||
json.teamID = teamID.value;
|
||||
json.p8 = p8.value;
|
||||
|
||||
element.value = JSON.stringify(json);
|
||||
}
|
||||
|
||||
function sync() {
|
||||
if(!element.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
let json = {};
|
||||
|
||||
try {
|
||||
json = JSON.parse(element.value);
|
||||
} catch (error) {
|
||||
console.error('Failed to parse secret key');
|
||||
}
|
||||
|
||||
teamID.value = json.teamID || '';
|
||||
keyID.value = json.keyID || '';
|
||||
p8.value = json.p8 || '';
|
||||
}
|
||||
|
||||
// function syncB() {
|
||||
// picker.value = element.value;
|
||||
// }
|
||||
|
||||
// element.parentNode.insertBefore(preview, element);
|
||||
|
||||
// update();
|
||||
sync();
|
||||
}
|
||||
});
|
||||
})(window);
|
73
public/scripts/views/forms/oauth-custom.js
Normal file
73
public/scripts/views/forms/oauth-custom.js
Normal file
|
@ -0,0 +1,73 @@
|
|||
(function (window) {
|
||||
"use strict";
|
||||
|
||||
//TODO: Make this generic
|
||||
|
||||
window.ls.container.get("view").add({
|
||||
selector: "data-forms-oauth-custom",
|
||||
controller: function (element) {
|
||||
// provider configuration for custom forms. Keys will be property names in JSON, values the elementIDs for the according inputs
|
||||
let providers = {
|
||||
"Microsoft": {
|
||||
"clientSecret": "oauth2MicrosoftClientSecret",
|
||||
"tenantId": "oauth2MicrosoftTenantId"
|
||||
},
|
||||
"Apple": {
|
||||
"keyId": "oauth2AppleKeyId",
|
||||
"teamId": "oauth2AppleTeamId",
|
||||
"p8": "oauth2AppleP8"
|
||||
}
|
||||
}
|
||||
let provider = element.getAttribute("data-forms-oauth-custom");
|
||||
if (!provider || !providers.hasOwnProperty(provider)) { console.error("Provider for custom form not set or unkown") }
|
||||
let config = providers[provider];
|
||||
|
||||
// Add Change Listeners for element
|
||||
element.addEventListener('change', sync);
|
||||
|
||||
// Get all inputs by id and register change event listener
|
||||
let elements = {};
|
||||
for (const key in config) {
|
||||
if (Object.hasOwnProperty.call(config, key)) {
|
||||
elements[key] = document.getElementById(config[key]);
|
||||
elements[key].addEventListener('change', update);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Build the JSON based on input in custom input fields
|
||||
function update() {
|
||||
let json = {};
|
||||
for (const key in elements) {
|
||||
if (Object.hasOwnProperty.call(elements, key)) {
|
||||
json[key] = elements[key].value
|
||||
}
|
||||
}
|
||||
|
||||
element.value = JSON.stringify(json);
|
||||
}
|
||||
|
||||
// When the JSON changes (on load) change values in custom input fields
|
||||
function sync() {
|
||||
if (!element.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
let json = {};
|
||||
|
||||
try {
|
||||
json = JSON.parse(element.value);
|
||||
} catch (error) {
|
||||
console.error('Failed to parse secret key');
|
||||
}
|
||||
|
||||
for (const key in elements) {
|
||||
if (Object.hasOwnProperty.call(elements, key)) {
|
||||
elements[key].value = json[key] || '';
|
||||
}
|
||||
}
|
||||
}
|
||||
sync();
|
||||
}
|
||||
});
|
||||
})(window);
|
|
@ -36,7 +36,7 @@ class Microsoft extends OAuth2
|
|||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize?'.\http_build_query([
|
||||
return 'https://login.microsoftonline.com/'.$this->getTenantId().'/oauth2/v2.0/authorize?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'state'=> \json_encode($this->state),
|
||||
|
@ -57,12 +57,12 @@ class Microsoft extends OAuth2
|
|||
|
||||
$accessToken = $this->request(
|
||||
'POST',
|
||||
'https://login.microsoftonline.com/common/oauth2/v2.0/token',
|
||||
'https://login.microsoftonline.com/'.$this->getTenantId().'/oauth2/v2.0/token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
'code' => $code,
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'client_secret' => $this->getClientSecret(),
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'grant_type' => 'authorization_code'
|
||||
|
@ -141,4 +141,39 @@ class Microsoft extends OAuth2
|
|||
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the Client Secret from the JSON stored in appSecret
|
||||
* @return string
|
||||
*/
|
||||
protected function getClientSecret(): string
|
||||
{
|
||||
$secret = $this->decodeJson();
|
||||
|
||||
return (isset($secret['clientSecret'])) ? $secret['clientSecret'] : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the JSON stored in appSecret
|
||||
* @return array
|
||||
*/
|
||||
protected function decodeJson(): array
|
||||
{
|
||||
try {
|
||||
$secret = \json_decode($this->appSecret, true);
|
||||
} catch (\Throwable $th) {
|
||||
throw new Exception('Invalid secret');
|
||||
}
|
||||
return $secret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the Tenant Id from the JSON stored in appSecret. Defaults to 'common' as a fallback
|
||||
* @return string
|
||||
*/
|
||||
protected function getTenantId(): string
|
||||
{
|
||||
$secret = $this->decodeJson();
|
||||
return (isset($secret['tenantId'])) ? $secret['tenantId'] : 'common';
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue