diff --git a/app/config/README.md b/app/config/README.md index e377e4d..4181e3e 100644 --- a/app/config/README.md +++ b/app/config/README.md @@ -57,6 +57,8 @@ Here is the list of available arguments and its usage: | spellCheckerLanguages | Array of languages to use with Electron's spell checker | [] | | ssoBasicAuthUser | Login that will be sent for basic_auth SSO login. | string | | ssoBasicAuthPasswordCommand | Command to execute, grab stdout and use it as a password for basic_auth SSO login. | string | +| ssoIntuneEnabled | Enable InTune Single-Sign-On | false +| ssoIntuneAuthUser | User (e-mail) to be used for InTune SSO login. | string | | trayIconEnabled | Enable tray icon | true | | url | Microsoft Teams URL | string | | useMutationTitleLogic | Use MutationObserver to update counter from title | true | diff --git a/app/config/index.js b/app/config/index.js index 117c655..fb1bec1 100644 --- a/app/config/index.js +++ b/app/config/index.js @@ -275,6 +275,16 @@ function argv(configPath, appVersion) { describe: 'Command to execute to retrieve password for SSO basic auth.', type: 'string' }, + ssoInTuneEnabled: { + default: false, + describe: 'Enable Single-Sign-On using Microsoft InTune.', + type: 'boolean' + }, + ssoInTuneAuthUser: { + default: '', + describe: 'User (e-mail) to use for InTune SSO.', + type: 'string' + }, trayIconEnabled: { default: true, describe: 'Enable tray icon', diff --git a/app/intune/index.js b/app/intune/index.js new file mode 100644 index 0000000..e4474f3 --- /dev/null +++ b/app/intune/index.js @@ -0,0 +1,91 @@ +const dbus = require('@homebridge/dbus-native'); +const { LucidLog } = require('lucid-log'); + +var sessionBus = dbus.sessionBus(); + +var intuneAccount = null; + +var brokerService = sessionBus.getService('com.microsoft.identity.broker1'); + +function processInTuneAccounts(logger, resp, ssoInTuneAuthUser) { + response = JSON.parse(resp); + if ('error' in response) { + logger.warn('Failed to retrieve InTune account list: ' + response.error.context); + return; + }; + + if (ssoInTuneAuthUser == '') { + intuneAccount = response.accounts[0]; + logger.debug('Using first available InTune account (' + intuneAccount.username + ')'); + } else { + for (account in response.accounts) { + if (account.username == ssoIntuneAuthUser) { + intuneAccount = account; + logger.debug('Found matching InTune account (' + intuneAccount.username + ')'); + break; + } + } + if (intuneAccount == null) { + logger.warn('Failed to find matching InTune account for ' + ssoIntuneAuthUser + '.'); + } + } +} + +exports.initSso = function initIntuneSso(logger, ssoInTuneAuthUser) { + logger.debug("Initializing InTune SSO"); + brokerService.getInterface( + '/com/microsoft/identity/broker1', + 'com.microsoft.identity.Broker1', function(err, broker) { + if (err) { + logger.warn('Failed to find microsoft-identity-broker DBus interface'); + return; + } + broker.getAccounts('0.0', '', JSON.stringify({'clientId': '88200948-af09-45a1-9c03-53cdcc75c183', 'redirectUri':'urn:ietf:oob'}), function(err, resp) { + if (err) { + logger.warn('Failed to communicate with microsoft-identity-broker'); + return; + } + processInTuneAccounts(logger, resp, ssoInTuneAuthUser); + }); + }); +} + +exports.setupUrlFilter = function setupUrlFilter(filter) { + filter.urls.push('https://login.microsoftonline.com/*'); +} + +exports.isSsoUrl = function isSsoUrl(url) { + return intuneAccount != null && url.startsWith('https://login.microsoftonline.com/'); +} + +function processPrtResponse(logger, resp, detail) { + response = JSON.parse(resp); + if ('error' in response) { + logger.warn('Failed to retrieve Intune SSO cookie: ' + response.error.context); + } else { + logger.debug('Adding SSO credential'); + detail.requestHeaders['X-Ms-Refreshtokencredential'] = response['cookieContent']; + } +} + +exports.addSsoCookie = function addIntuneSsoCookie(logger, detail, callback) { + logger.debug('Retrieving InTune SSO cookie'); + if (intuneAccount == null) { + logger.info("InTune SSO not active"); + callback({ + requestHeaders: detail.requestHeaders + }); + return; + } + brokerService.getInterface( + '/com/microsoft/identity/broker1', + 'com.microsoft.identity.Broker1', function(err, broker) { + broker.acquirePrtSsoCookie('0.0', '', JSON.stringify({'ssoUrl':detail.url, 'account':intuneAccount, 'authParameters':{'authority':'https://login.microsoftonline.com/common/'}}), function(err, resp) { + processPrtResponse(logger, resp, detail); + callback({ + requestHeaders: detail.requestHeaders + }); + }); + }); +} + diff --git a/app/mainAppWindow/index.js b/app/mainAppWindow/index.js index 4f33baa..043237c 100644 --- a/app/mainAppWindow/index.js +++ b/app/mainAppWindow/index.js @@ -16,6 +16,7 @@ const TrayIconChooser = require('../browser/tools/trayIconChooser'); const { AppConfiguration } = require('../appConfiguration'); const connMgr = require('../connectionManager'); const fs = require('fs'); +const intune = require('../intune'); /** * @type {TrayIconChooser} @@ -65,6 +66,10 @@ exports.onAppReady = async function onAppReady(configGroup) { levels: config.appLogLevels.split(',') }); + if (config.ssoInTuneEnabled) { + intune.initSso(logger, config.ssoInTuneAuthUser); + } + window = await createWindow(); if (config.trayIconEnabled) { @@ -323,12 +328,16 @@ function setImgSrcSecurityPolicy(policies) { * @param {Electron.BeforeSendResponse} callback */ function onBeforeSendHeadersHandler(detail, callback) { - if (detail.url.startsWith(customBGServiceUrl.href)) { - detail.requestHeaders['Access-Control-Allow-Origin'] = '*'; + if (intune.isSsoUrl(detail.url)) { + intune.addSsoCookie(logger, detail, callback); + } else { + if (detail.url.startsWith(customBGServiceUrl.href)) { + detail.requestHeaders['Access-Control-Allow-Origin'] = '*'; + } + callback({ + requestHeaders: detail.requestHeaders + }); } - callback({ - requestHeaders: detail.requestHeaders - }); } /** @@ -409,6 +418,7 @@ function addEventHandlers() { function getWebRequestFilterFromURL() { const filter = customBGServiceUrl.protocol === 'http:' ? { urls: ['http://*/*'] } : { urls: ['https://*/*'] }; + intune.setupUrlFilter(filter); return filter; } diff --git a/com.github.IsmaelMartinez.teams_for_linux.appdata.xml b/com.github.IsmaelMartinez.teams_for_linux.appdata.xml index ae44d16..0fe11ed 100644 --- a/com.github.IsmaelMartinez.teams_for_linux.appdata.xml +++ b/com.github.IsmaelMartinez.teams_for_linux.appdata.xml @@ -14,6 +14,13 @@ https://github.com/IsmaelMartinez/teams-for-linux/issues com.github.IsmaelMartinez.teams_for_linux.desktop + + +
    +
  • Add support for Single Sign On using Microsoft Intune
  • +
+
+
    diff --git a/package.json b/package.json index 66b7a9a..e79bd81 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "teams-for-linux", - "version": "1.5.2", + "version": "1.5.3", "main": "app/index.js", "description": "Unofficial client for Microsoft Teams for Linux", "homepage": "https://github.com/IsmaelMartinez/teams-for-linux", @@ -40,6 +40,7 @@ "release": "electron-builder" }, "dependencies": { + "@homebridge/dbus-native": "0.6.0", "@electron/remote": "^2.1.2", "electron-is-dev": "2.0.0", "electron-store": "8.2.0", diff --git a/yarn.lock b/yarn.lock index 3fe93d2..ea11a3c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -119,6 +119,29 @@ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.0.0.tgz#1a9e4b4c96d8c7886e0110ed310a0135144a1691" integrity sha512-RThY/MnKrhubF6+s1JflwUjPEsnCEmYCWwqa/aRISKWNXGZ9epUwft4bUMM35SdKF9xvBrLydAM1RDHd1Z//ZQ== +"@homebridge/dbus-native@0.6.0": + version "0.6.0" + resolved "https://registry.yarnpkg.com/@homebridge/dbus-native/-/dbus-native-0.6.0.tgz#25052dd03216b977298e4c9db19b7aeb1d2363f4" + integrity sha512-xObqQeYHTXmt6wsfj10+krTo4xbzR9BgUfX2aQ+edDC9nc4ojfzLScfXCh3zluAm6UCowKw+AFfXn6WLWUOPkg== + dependencies: + "@homebridge/long" "^5.2.1" + "@homebridge/put" "^0.0.8" + event-stream "^4.0.1" + hexy "^0.3.5" + minimist "^1.2.6" + safe-buffer "^5.1.2" + xml2js "^0.6.2" + +"@homebridge/long@^5.2.1": + version "5.2.1" + resolved "https://registry.yarnpkg.com/@homebridge/long/-/long-5.2.1.tgz#1c7568775b78e1a0fd75a7b3fa7a995f0388ab37" + integrity sha512-i5Df8R63XNPCn+Nj1OgAoRdw9e+jHUQb3CNUbvJneI2iu3j4+OtzQj+5PA1Ce+747NR1SPqZSvyvD483dOT3AA== + +"@homebridge/put@^0.0.8": + version "0.0.8" + resolved "https://registry.yarnpkg.com/@homebridge/put/-/put-0.0.8.tgz#4b8b99f2c4d58bc762718863699df2c5bc0b4b8a" + integrity sha512-mwxLHHqKebOmOSU0tsPEWQSBHGApPhuaqtNpCe7U+AMdsduweANiu64E9SXXUtdpyTjsOpgSMLhD1+kbLHD2gA== + "@humanwhocodes/config-array@^0.12.3": version "0.12.3" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.12.3.tgz#a6216d90f81a30bedd1d4b5d799b47241f318072" @@ -795,6 +818,11 @@ dotenv@^9.0.2: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-9.0.2.tgz#dacc20160935a37dea6364aa1bef819fb9b6ab05" integrity sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg== +duplexer@^0.1.1, duplexer@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" + integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== + eastasianwidth@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" @@ -1012,6 +1040,19 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +event-stream@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-4.0.1.tgz#4092808ec995d0dd75ea4580c1df6a74db2cde65" + integrity sha512-qACXdu/9VHPBzcyhdOWR5/IahhGMf0roTeZJfzz077GwylcDd90yOHLouhmv7GJ5XzPi6ekaQWd8AvPP2nOvpA== + dependencies: + duplexer "^0.1.1" + from "^0.1.7" + map-stream "0.0.7" + pause-stream "^0.0.11" + split "^1.0.1" + stream-combiner "^0.2.2" + through "^2.3.8" + extract-zip@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a" @@ -1116,6 +1157,11 @@ form-data@^4.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" +from@^0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe" + integrity sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g== + fs-extra@^10.0.0, fs-extra@^10.1.0: version "10.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" @@ -1302,6 +1348,11 @@ hasown@^2.0.0: dependencies: function-bind "^1.1.2" +hexy@^0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/hexy/-/hexy-0.3.5.tgz#adcd5ee47d66aca3581d771743a509a5176e45f9" + integrity sha512-UCP7TIZPXz5kxYJnNOym+9xaenxCLor/JyhKieo8y8/bJWunGh9xbhy3YrgYJUQ87WwfXGm05X330DszOfINZw== + hosted-git-info@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.1.0.tgz#827b82867e9ff1c8d0c4d9d53880397d2c86d224" @@ -1585,6 +1636,11 @@ lucid-log@^0.0.3: dependencies: chalk "^4.1.2" +map-stream@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.0.7.tgz#8a1f07896d82b10926bd3744a2420009f88974a8" + integrity sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ== + matcher@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/matcher/-/matcher-3.0.0.tgz#bd9060f4c5b70aa8041ccc6f80368760994f30ca" @@ -1821,6 +1877,13 @@ path-scurry@^1.10.2: lru-cache "^10.2.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0" +pause-stream@^0.0.11: + version "0.0.11" + resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445" + integrity sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A== + dependencies: + through "~2.3" + pend@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" @@ -1951,6 +2014,11 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" +safe-buffer@^5.1.2: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" @@ -1963,6 +2031,11 @@ sanitize-filename@^1.6.3: dependencies: truncate-utf8-bytes "^1.0.0" +sax@>=0.6.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f" + integrity sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg== + sax@^1.2.4: version "1.3.0" resolved "https://registry.yarnpkg.com/sax/-/sax-1.3.0.tgz#a5dbe77db3be05c9d1ee7785dbd3ea9de51593d0" @@ -2043,6 +2116,13 @@ source-map@^0.6.0: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +split@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" + integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg== + dependencies: + through "2" + sprintf-js@^1.1.2: version "1.1.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a" @@ -2053,6 +2133,14 @@ stat-mode@^1.0.0: resolved "https://registry.yarnpkg.com/stat-mode/-/stat-mode-1.0.0.tgz#68b55cb61ea639ff57136f36b216a291800d1465" integrity sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg== +stream-combiner@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.2.2.tgz#aec8cbac177b56b6f4fa479ced8c1912cee52858" + integrity sha512-6yHMqgLYDzQDcAkL+tjJDC5nSNuNIx0vZtRZeiPh7Saef7VHX9H5Ijn9l2VIol2zaNYlYEX6KyuT/237A58qEQ== + dependencies: + duplexer "~0.1.1" + through "~2.3.4" + "string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" @@ -2129,6 +2217,11 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== +through@2, through@^2.3.8, through@~2.3, through@~2.3.4: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== + tmp-promise@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/tmp-promise/-/tmp-promise-3.0.3.tgz#60a1a1cc98c988674fcbfd23b6e3367bdeac4ce7" @@ -2241,11 +2334,24 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== +xml2js@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.6.2.tgz#dd0b630083aa09c161e25a4d0901e2b2a929b499" + integrity sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA== + dependencies: + sax ">=0.6.0" + xmlbuilder "~11.0.0" + xmlbuilder@>=11.0.1, xmlbuilder@^15.1.1: version "15.1.1" resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-15.1.1.tgz#9dcdce49eea66d8d10b42cae94a79c3c8d0c2ec5" integrity sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg== +xmlbuilder@~11.0.0: + version "11.0.1" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" + integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== + y18n@^5.0.5: version "5.0.8" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"