1
0
Fork 0
mirror of synced 2024-06-25 01:30:56 +12:00

feat: Makes Microsoft OAuth Provider configureable

This commit is contained in:
Simon Trockel 2022-01-17 00:46:12 +01:00
parent fb2ec0355a
commit 9922a6d6cf
10 changed files with 1083 additions and 901 deletions

View file

@ -127,7 +127,7 @@ return [ // Ordered by ABC.
'icon' => 'icon-windows',
'enabled' => true,
'sandbox' => false,
'form' => false,
'form' => 'microsoft.phtml',
'beta' => false,
'mock' => false,
],

View file

@ -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_view = new View(__DIR__.'/oauth/'.$this->escape($form));
echo $form_view
->setParam("provider",$provider)
->render();
?>
<?php endif; ?>
<div class="info row thin margin-bottom margin-top">

View file

@ -0,0 +1,7 @@
<?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-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}}" />

View 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-microsoft 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}}" />

View file

@ -58,6 +58,7 @@ const configApp = {
'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-microsoft.js',
'public/scripts/views/forms/password-meter.js',
'public/scripts/views/forms/pell.js',
'public/scripts/views/forms/required.js',

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -782,6 +782,10 @@ console.log('old',minLink);minDistance=distance;minElement=title;minLink=links[i
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||'';}
sync();}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-oauth-microsoft",controller:function(element){let clientSecret=document.getElementById("oauth2MicrosoftClientSecret");let tenantId=document.getElementById("oauth2MicrosoftTenantId");element.addEventListener('change',sync);clientSecret.addEventListener('change',update);tenantId.addEventListener('change',update);function update(){let json={};json.clientSecret=clientSecret.value;json.tenantId=tenantId.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');}
clientSecret.value=json.clientSecret||'';tenantId.value=json.tenantId||'';}
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;}

View file

@ -0,0 +1,50 @@
(function (window) {
"use strict";
//TODO: Make this generic
window.ls.container.get("view").add({
selector: "data-forms-oauth-microsoft",
controller: function (element) {
// element contains the final secret
// Get all custom input fields by their ID
let clientSecret = document.getElementById("oauth2MicrosoftClientSecret");
let tenantId = document.getElementById("oauth2MicrosoftTenantId");
// Add Change Listeners for element and all custom input fields
element.addEventListener('change', sync);
clientSecret.addEventListener('change', update);
tenantId.addEventListener('change', update);
// Build the JSON based on input in custom input fields
function update() {
let json = {};
json.clientSecret = clientSecret.value;
json.tenantId = tenantId.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');
}
clientSecret.value = json.clientSecret || '';
tenantId.value = json.tenantId || '';
}
sync();
}
});
})(window);

View file

@ -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';
}
}