├── .gitignore ├── Locale └── fr_FR │ └── translations.php ├── Template ├── user │ ├── authentication.php │ ├── create_remote.php │ └── external.php ├── auth │ └── login.php └── config │ └── integration.php ├── Makefile ├── Schema ├── Mysql.php ├── Postgres.php └── Sqlite.php ├── .github ├── issue_template.md └── workflows │ └── unit_tests.yml ├── Controller └── OAuthController.php ├── Test └── PluginTest.php ├── LICENSE ├── Plugin.php ├── README.md ├── Auth └── GenericOAuth2Provider.php └── User └── GenericOAuth2UserProvider.php /.gitignore: -------------------------------------------------------------------------------- 1 | *.zip 2 | -------------------------------------------------------------------------------- /Locale/fr_FR/translations.php: -------------------------------------------------------------------------------- 1 | form->label(t('OAuth2 ID'), 'oauth2_user_id') ?> 2 | form->text('oauth2_user_id', $values, $errors) ?> -------------------------------------------------------------------------------- /Template/user/create_remote.php: -------------------------------------------------------------------------------- 1 | form->label(t('OAuth2 ID'), 'oauth2_user_id') ?> 2 | form->text('oauth2_user_id', $values, $errors) ?> -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | plugin=OAuth2 2 | 3 | all: 4 | @ echo "Build archive for plugin ${plugin} version=${version}" 5 | @ git archive HEAD --prefix=${plugin}/ --format=zip -o ${plugin}-${version}.zip 6 | -------------------------------------------------------------------------------- /Schema/Mysql.php: -------------------------------------------------------------------------------- 1 | exec('ALTER TABLE users ADD COLUMN oauth2_user_id VARCHAR(255)'); 12 | } 13 | -------------------------------------------------------------------------------- /Schema/Postgres.php: -------------------------------------------------------------------------------- 1 | exec('ALTER TABLE users ADD COLUMN oauth2_user_id VARCHAR(255)'); 12 | } 13 | -------------------------------------------------------------------------------- /Schema/Sqlite.php: -------------------------------------------------------------------------------- 1 | exec('ALTER TABLE users ADD COLUMN oauth2_user_id VARCHAR(255)'); 12 | } 13 | -------------------------------------------------------------------------------- /.github/issue_template.md: -------------------------------------------------------------------------------- 1 | **Please, do not create duplicate issues** 2 | 3 | 4 | ### Actual behaviour 5 | 6 | 7 | ### Expected behaviour 8 | 9 | 10 | ### Steps to reproduce 11 | 12 | 13 | ### Configuration 14 | 15 | - Plugin version: 16 | - Kanboard version: 17 | - Database type and version: 18 | - PHP version: 19 | - OS: 20 | - Browser: 21 | 22 | -------------------------------------------------------------------------------- /Template/auth/login.php: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /Controller/OAuthController.php: -------------------------------------------------------------------------------- 1 | step1('OAuth2'); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Template/user/external.php: -------------------------------------------------------------------------------- 1 |

2 | 3 |
4 | user->isCurrentUser($user['id'])): ?> 5 | 6 | url->link(t('Link OAuth2 account'), 'OAuthController', 'handler', array('plugin' => 'OAuth2'), true) ?> 7 | 8 | url->link(t('Unlink my OAuth2 account'), 'OAuthController', 'unlink', array('backend' => 'OAuth2'), true) ?> 9 | 10 | 11 | 12 | 13 |
14 | -------------------------------------------------------------------------------- /Test/PluginTest.php: -------------------------------------------------------------------------------- 1 | container); 14 | $this->assertSame(null, $plugin->initialize()); 15 | $this->assertSame(null, $plugin->onStartup()); 16 | $this->assertNotEmpty($plugin->getPluginName()); 17 | $this->assertNotEmpty($plugin->getPluginDescription()); 18 | $this->assertNotEmpty($plugin->getPluginAuthor()); 19 | $this->assertNotEmpty($plugin->getPluginVersion()); 20 | $this->assertNotEmpty($plugin->getPluginHomepage()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Frédéric Guillot 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Plugin.php: -------------------------------------------------------------------------------- 1 | authenticationManager->register(new GenericOAuth2Provider($this->container)); 15 | $this->applicationAccessMap->add('OAuthController', 'handler', Role::APP_PUBLIC); 16 | 17 | $this->route->addRoute('/oauth/callback', 'OAuthController', 'handler', 'OAuth2'); 18 | 19 | $this->template->hook->attach('template:auth:login-form:after', 'OAuth2:auth/login', [ 20 | 'oauth2_custom_login_text' => $this->configModel->get('oauth2_custom_login_text'), 21 | ]); 22 | $this->template->hook->attach('template:config:integrations', 'OAuth2:config/integration'); 23 | $this->template->hook->attach('template:user:external', 'OAuth2:user/external'); 24 | $this->template->hook->attach('template:user:authentication:form', 'OAuth2:user/authentication'); 25 | $this->template->hook->attach('template:user:create-remote:form', 'OAuth2:user/create_remote'); 26 | } 27 | 28 | public function onStartup() 29 | { 30 | Translator::load($this->languageModel->getCurrentLanguage(), __DIR__.'/Locale'); 31 | } 32 | 33 | public function getPluginName() 34 | { 35 | return 'OAuth2'; 36 | } 37 | 38 | public function getPluginDescription() 39 | { 40 | return t('Generic OAuth2 authentication plugin'); 41 | } 42 | 43 | public function getPluginAuthor() 44 | { 45 | return 'Frédéric Guillot'; 46 | } 47 | 48 | public function getPluginVersion() 49 | { 50 | return '1.0.2'; 51 | } 52 | 53 | public function getPluginHomepage() 54 | { 55 | return 'https://github.com/kanboard/plugin-oauth2'; 56 | } 57 | 58 | public function getCompatibleVersion() 59 | { 60 | return '>=1.0.37'; 61 | } 62 | } 63 | 64 | -------------------------------------------------------------------------------- /.github/workflows/unit_tests.yml: -------------------------------------------------------------------------------- 1 | name: Unit Tests 2 | 3 | on: 4 | pull_request: 5 | branches: [ master ] 6 | 7 | jobs: 8 | Sqlite: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout Kanboard repo 12 | uses: actions/checkout@v2 13 | with: 14 | repository: kanboard/kanboard 15 | - name: Checkout Plugin repo 16 | uses: actions/checkout@v2 17 | with: 18 | path: plugins/OAuth2 19 | - name: Install dependencies 20 | run: composer install --prefer-dist --no-progress --no-suggest 21 | - name: Unit tests with Sqlite 22 | run: ./vendor/bin/phpunit -c tests/units.sqlite.xml plugins/OAuth2/Test/ 23 | 24 | Postgres: 25 | runs-on: ubuntu-latest 26 | services: 27 | postgres: 28 | image: postgres:9.4 29 | env: 30 | POSTGRES_USER: postgres 31 | POSTGRES_PASSWORD: postgres 32 | POSTGRES_DB: kanboard_unit_test 33 | ports: 34 | - 5432:5432 35 | options: >- 36 | --health-cmd pg_isready 37 | --health-interval 10s 38 | --health-timeout 5s 39 | --health-retries 5 40 | steps: 41 | - name: Checkout Kanboard repo 42 | uses: actions/checkout@v2 43 | with: 44 | repository: kanboard/kanboard 45 | - name: Checkout Plugin repo 46 | uses: actions/checkout@v2 47 | with: 48 | path: plugins/OAuth2 49 | - name: Install dependencies 50 | run: composer install --prefer-dist --no-progress --no-suggest 51 | - name: Unit tests with Postgres 52 | run: ./vendor/bin/phpunit -c tests/units.postgres.xml plugins/OAuth2/Test/ 53 | env: 54 | DB_HOSTNAME: 127.0.0.1 55 | DB_PORT: ${{ job.services.postgres.ports[5432] }} 56 | 57 | MySQL: 58 | runs-on: ubuntu-latest 59 | services: 60 | mysql: 61 | image: mysql:5.7 62 | env: 63 | MYSQL_ROOT_PASSWORD: "kanboard" 64 | MYSQL_DATABASE: "kanboard_unit_test" 65 | MYSQL_USER: "kanboard" 66 | MYSQL_PASSWORD: "kanboard" 67 | ports: 68 | - 3306:3306 69 | options: >- 70 | --health-cmd="mysqladmin ping" 71 | --health-interval 10s 72 | --health-timeout 5s 73 | --health-retries 10 74 | steps: 75 | - name: Checkout Kanboard repo 76 | uses: actions/checkout@v2 77 | with: 78 | repository: kanboard/kanboard 79 | - name: Checkout Plugin repo 80 | uses: actions/checkout@v2 81 | with: 82 | path: plugins/OAuth2 83 | - name: Install dependencies 84 | run: composer install --prefer-dist --no-progress --no-suggest 85 | - name: Unit tests with MySQL 86 | run: ./vendor/bin/phpunit -c tests/units.mysql.xml plugins/OAuth2/Test/ 87 | env: 88 | DB_HOSTNAME: 127.0.0.1 89 | DB_USERNAME: kanboard 90 | DB_PASSWORD: kanboard 91 | DB_NAME: kanboard_unit_test 92 | DB_PORT: ${{ job.services.mysql.ports[3306] }} 93 | -------------------------------------------------------------------------------- /Template/config/integration.php: -------------------------------------------------------------------------------- 1 |

2 |
3 | form->label(t('Callback URL'), 'oauth2_callback_url') ?> 4 | 5 | 6 | form->label(t('Client ID'), 'oauth2_client_id') ?> 7 | form->password('oauth2_client_id', $values) ?> 8 | 9 | form->label(t('Client Secret'), 'oauth2_client_secret') ?> 10 | form->password('oauth2_client_secret', $values) ?> 11 | 12 | form->label(t('Authorize URL'), 'oauth2_authorize_url') ?> 13 | form->text('oauth2_authorize_url', $values) ?> 14 | 15 | form->label(t('Token URL'), 'oauth2_token_url') ?> 16 | form->text('oauth2_token_url', $values) ?> 17 | 18 | form->label(t('User API URL'), 'oauth2_user_api_url') ?> 19 | form->text('oauth2_user_api_url', $values) ?> 20 | 21 | form->label(t('Scopes'), 'oauth2_scopes') ?> 22 | form->text('oauth2_scopes', $values) ?> 23 | 24 | form->label(t('Username Key'), 'oauth2_key_username') ?> 25 | form->text('oauth2_key_username', $values) ?> 26 | 27 | form->label(t('Name Key'), 'oauth2_key_name') ?> 28 | form->text('oauth2_key_name', $values) ?> 29 | 30 | form->label(t('Email Key'), 'oauth2_key_email') ?> 31 | form->text('oauth2_key_email', $values) ?> 32 | 33 | form->label(t('User ID Key'), 'oauth2_key_user_id') ?> 34 | form->text('oauth2_key_user_id', $values) ?> 35 | 36 | form->hidden('oauth2_split_keys', array('oauth2_split_keys' => 0)) ?> 37 | form->checkbox('oauth2_split_keys', t('Use composite keys?'), 1, isset($values['oauth2_split_keys']) && $values['oauth2_split_keys'] == 1) ?> 38 |

39 | 40 | form->hidden('oauth2_account_creation', array('oauth2_account_creation' => 0)) ?> 41 | form->checkbox('oauth2_account_creation', t('Allow Account Creation'), 1, isset($values['oauth2_account_creation']) && $values['oauth2_account_creation'] == 1) ?> 42 | 43 | form->label(t('Allow account creation only for those domains'), 'oauth2_email_domains') ?> 44 | form->text('oauth2_email_domains', $values) ?> 45 |

46 | 47 | form->label(t('Groups Key'), 'oauth2_key_groups') ?> 48 | form->text('oauth2_key_groups', $values) ?> 49 |

50 | 51 | form->label(t('Group Filter'), 'oauth2_key_group_filter') ?> 52 | form->text('oauth2_key_group_filter', $values) ?> 53 |

54 | 55 | form->label(t('Automatically add user to a group'), 'oauth2_custom_group') ?> 56 | form->text('oauth2_custom_group', $values) ?> 57 |

58 | 59 | form->label(t('Custom Login Text'), 'oauth2_custom_login_text') ?> 60 | form->text('oauth2_custom_login_text', $values) ?> 61 |

62 | 63 |
64 | 65 |
66 |
67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | OAuth2 Authentication 2 | ===================== 3 | 4 | Generic OAuth2 authentication plugin. 5 | 6 | Author 7 | ------ 8 | 9 | - Frédéric Guillot 10 | - License MIT 11 | 12 | Requirements 13 | ------------ 14 | 15 | - Kanboard >= 1.0.37 16 | 17 | Installation 18 | ------------ 19 | 20 | You have the choice between 3 methods: 21 | 22 | 1. Install the plugin from the Kanboard plugin manager in one click 23 | 2. Download the zip file and decompress everything under the directory `plugins/OAuth2` 24 | 3. Clone this repository into the folder `plugins/OAuth2` 25 | 26 | Note: Plugin folder is case-sensitive. 27 | 28 | Configuration 29 | ------------- 30 | 31 | > **Note:** Also works with most OpenID Providers 32 | 33 | Go to the application settings > integrations > OAuth2 Authentication. 34 | 35 | ### 1) Create a new application on the OAuth2 provider 36 | 37 | Go to the third-party authentication provider and add a new application. 38 | Copy and paste the **Kanboard callback URL** and generate a new set of tokens. 39 | 40 | The third-party provider will returns a **Client ID** and a **Client Secret**. 41 | Copy those values in the Kanboard's settings. 42 | 43 | ### 2) Configure the provider in Kanboard 44 | 45 | - **Client ID**: Unique ID that comes from the third-party provider 46 | - **Client Secret**: Unique token that comes from the third-party provider 47 | - **Authorize URL**: URL used for authorization 48 | - **Token URL**: URL used to get tokens from third-party provider 49 | - **User API URL**: URL used to fetch user profile after authentication 50 | - **Username Key**: Key used to fetch the username from the user API response 51 | - **Name Key**: Key used to fetch the full name 52 | - **Email Key**: Key used to fetch the user email 53 | - **User ID Key**: Key used to fetch the unique user ID 54 | 55 | Notes 56 | ----- 57 | 58 | If "Allow Account Creation" checkbox is checked, anyone who goes to the login page, clicks the 59 | "OAuth2 Login" link, and correctly validates with your Oauth2 backend will automatically have 60 | their account created. No need to create the user in Kanboard or to use the "Invite people" 61 | link in the users area. 62 | 63 | Examples 64 | -------- 65 | 66 | Example for Github OAuth2: 67 | 68 | - **Authorize URL**: `https://github.com/login/oauth/authorize` 69 | - **Token URL**: `https://github.com/login/oauth/access_token` 70 | - **User API URL**: `https://api.github.com/user` 71 | - **Username Key**: `login` 72 | - **Name Key**: `name` 73 | - **Email Key**: `email` 74 | - **User ID Key**: `id` 75 | 76 | Example for Salesforce: 77 | 78 | - **Authorize URL**: `https://login.salesforce.com/services/oauth2/authorize` 79 | - **Token URL**: `https://login.salesforce.com/services/oauth2/token` 80 | - **User API URL**: `https://login.salesforce.com/services/oauth2/userinfo` 81 | - **Username Key**: `nickname` 82 | - **Name Key**: `name` 83 | - **Email Key**: `email` 84 | - **User ID Key**: `user_id` 85 | 86 | Example for Discord: 87 | 88 | - **Authorize URL**: `https://discord.com/api/oauth2/authorize` 89 | - **Token URL**: `https://discord.com/api/oauth2/token` 90 | - **User API URL**: `https://discordapp.com/api/users/@me` 91 | - **Scopes**: `email identify` 92 | - **Username Key**: `username` 93 | - **Name Key**: `username` 94 | - **Email Key**: `email` 95 | - **User ID Key**: `id` 96 | 97 | Example for Gitea: 98 | 99 | - **Authorize URL**: `https://try.gitea.io/login/oauth/authorize` 100 | - **Token URL**: `https://try.gitea.io/login/oauth/access_token` 101 | - **User API URL**: `https://try.gitea.io/login/oauth/userinfo` 102 | - **Scopes**: `openid profile email groups` 103 | - **Username Key**: `preferred_username` 104 | - **Name Key**: `name` 105 | - **Email Key**: `email` 106 | - **User ID Key**: `sub` 107 | 108 | Example for Slack: 109 | 110 | - **Authorize URL**: `https://slack.com/openid/connect/authorize` 111 | - **Token URL**: `https://slack.com/api/openid.connect.token` 112 | - **User API URL**: `https://slack.com/api/openid.connect.userInfo` 113 | - **Scopes**: `openid profile email` 114 | - **Username Key**: `name` 115 | - **Name Key**: `name` 116 | - **Email Key**: `email` 117 | - **User ID Key**: `sub` 118 | 119 | Example for Azure AD (find the URLs with proper UUIDs in your Azure app page): 120 | 121 | - **Authorize URL**: `https://login.microsoftonline.com//oauth2/v2.0/authorize` 122 | - **Token URL**: `https://login.microsoftonline.com//oauth2/v2.0/token` 123 | - **User API URL**: `https://graph.microsoft.com/v1.0/me` 124 | - **Scopes**: `User.Read` 125 | - **Username Key**: `userPrincipalName` 126 | - **Name Key**: `displayName` 127 | - **Email Key**: `mail` 128 | - **User ID Key**: `id` 129 | 130 | Example for self-hosted Authentik: 131 | 132 | - **Authorize URL**: `https://auth.domain.tld/application/o/authorize/` 133 | - **Token URL**: `https://auth.domain.tld/application/o/token/` 134 | - **User API URL**: `https://auth.domain.tld/application/o/userinfo/` 135 | - **Scopes**: `openid profile email` 136 | - **Username Key**: `preferred_username` 137 | - **Name Key**: `name` 138 | - **Email Key**: `email` 139 | - **User ID Key**: `sub` 140 | -------------------------------------------------------------------------------- /Auth/GenericOAuth2Provider.php: -------------------------------------------------------------------------------- 1 | getProfile(); 61 | 62 | if (! empty($profile)) { 63 | $this->userInfo = new GenericOAuth2UserProvider($this->container, $profile); 64 | return true; 65 | } 66 | 67 | return false; 68 | } 69 | 70 | /** 71 | * Set Code 72 | * 73 | * @access public 74 | * @param string $code 75 | * @return $this 76 | */ 77 | public function setCode($code) 78 | { 79 | $this->code = $code; 80 | return $this; 81 | } 82 | 83 | /** 84 | * Get user object 85 | * 86 | * @access public 87 | * @return GenericOAuth2UserProvider 88 | */ 89 | public function getUser() 90 | { 91 | return $this->userInfo; 92 | } 93 | 94 | /** 95 | * Get configured OAuth2 service 96 | * 97 | * @access public 98 | * @return \Kanboard\Core\Http\OAuth2 99 | */ 100 | public function getService() 101 | { 102 | if (empty($this->service)) { 103 | $this->service = $this->oauth->createService( 104 | $this->getClientId(), 105 | $this->getClientSecret(), 106 | $this->helper->url->to('OAuthController', 'handler', array('plugin' => 'OAuth2'), '', true), 107 | $this->getOAuthAuthorizeUrl(), 108 | $this->getOAuthTokenUrl(), 109 | $this->getScopes() 110 | ); 111 | } 112 | 113 | return $this->service; 114 | } 115 | 116 | /** 117 | * Get user profile 118 | * 119 | * @access public 120 | * @return array 121 | */ 122 | public function getProfile() 123 | { 124 | $token = $this->getService()->getAccessToken($this->code); 125 | 126 | if (DEBUG) { 127 | $this->logger->debug(__METHOD__.': Got access token: '.(empty($token) ? 'No' : 'Yes')); 128 | $this->logger->debug(__METHOD__.': Fetch user profile from '.$this->getUserAPiUrl()); 129 | } 130 | 131 | return $this->httpClient->getJson( 132 | $this->getUserAPiUrl(), 133 | array($this->getService()->getAuthorizationHeader()) 134 | ); 135 | } 136 | 137 | /** 138 | * Unlink user 139 | * 140 | * @access public 141 | * @param integer $userId 142 | * @return bool 143 | */ 144 | public function unlink($userId) 145 | { 146 | return $this->userModel->update(array( 147 | 'id' => $userId, 148 | 'oauth2_user_id' => '', 149 | )); 150 | } 151 | 152 | /** 153 | * Get client id 154 | * 155 | * @access public 156 | * @return string 157 | */ 158 | public function getClientId() 159 | { 160 | return $this->configModel->get('oauth2_client_id'); 161 | } 162 | 163 | /** 164 | * Get scopes 165 | * 166 | * @access public 167 | * @return array 168 | */ 169 | public function getScopes() 170 | { 171 | return explode(" ", $this->configModel->get('oauth2_scopes')); 172 | } 173 | 174 | 175 | /** 176 | * Get client secret 177 | * 178 | * @access public 179 | * @return string 180 | */ 181 | public function getClientSecret() 182 | { 183 | return $this->configModel->get('oauth2_client_secret'); 184 | } 185 | 186 | /** 187 | * Get authorize url 188 | * 189 | * @access public 190 | * @return string 191 | */ 192 | public function getOAuthAuthorizeUrl() 193 | { 194 | return $this->configModel->get('oauth2_authorize_url'); 195 | } 196 | 197 | /** 198 | * Get token url 199 | * 200 | * @access public 201 | * @return string 202 | */ 203 | public function getOAuthTokenUrl() 204 | { 205 | return $this->configModel->get('oauth2_token_url'); 206 | } 207 | 208 | /** 209 | * Get User API url 210 | * 211 | * @access public 212 | * @return string 213 | */ 214 | public function getUserAPiUrl() 215 | { 216 | return $this->configModel->get('oauth2_user_api_url'); 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /User/GenericOAuth2UserProvider.php: -------------------------------------------------------------------------------- 1 | userData = $user; 33 | } 34 | 35 | /** 36 | * Return true to allow automatic user creation 37 | * 38 | * @access public 39 | * @return boolean 40 | */ 41 | public function isUserCreationAllowed() 42 | { 43 | return $this->configModel->get('oauth2_account_creation', 0) == 1; 44 | } 45 | 46 | /** 47 | * Get username 48 | * 49 | * @access public 50 | * @return string 51 | */ 52 | public function getUsername() 53 | { 54 | if ($this->isUserCreationAllowed()) { 55 | return $this->getKey('oauth2_key_username'); 56 | } 57 | 58 | return ''; 59 | } 60 | 61 | /** 62 | * Get external id column name 63 | * 64 | * @access public 65 | * @return string 66 | */ 67 | public function getExternalIdColumn() 68 | { 69 | return 'oauth2_user_id'; 70 | } 71 | 72 | /** 73 | * Get extra user attributes 74 | * 75 | * @access public 76 | * @return array 77 | */ 78 | public function getExtraAttributes() 79 | { 80 | if ($this->isUserCreationAllowed()) { 81 | return array( 82 | 'is_ldap_user' => 1, 83 | 'disable_login_form' => 1, 84 | ); 85 | } 86 | 87 | return array(); 88 | } 89 | 90 | /** 91 | * Get internal id 92 | * 93 | * If a value is returned the user properties won't be updated in the local database 94 | * 95 | * @access public 96 | * @return integer 97 | */ 98 | public function getInternalId() 99 | { 100 | return ''; 101 | } 102 | 103 | /** 104 | * Get external id 105 | * 106 | * @access public 107 | * @return string 108 | */ 109 | public function getExternalId() 110 | { 111 | return $this->getKey('oauth2_key_user_id'); 112 | } 113 | 114 | /** 115 | * Get user role 116 | * 117 | * Return an empty string to not override role stored in the database 118 | * 119 | * @access public 120 | * @return string 121 | */ 122 | public function getRole() 123 | { 124 | return ''; 125 | } 126 | 127 | /** 128 | * Get user full name 129 | * 130 | * @access public 131 | * @return string 132 | */ 133 | public function getName() 134 | { 135 | return $this->getKey('oauth2_key_name'); 136 | } 137 | 138 | /** 139 | * Get user email 140 | * 141 | * @access public 142 | * @return string 143 | */ 144 | public function getEmail() 145 | { 146 | return $this->getKey('oauth2_key_email'); 147 | } 148 | 149 | /** 150 | * Check if group is in filter 151 | * 152 | * @access protected 153 | * @param string $group 154 | * @return boolean 155 | */ 156 | protected function isGroupInFilter(string $group, array $filter) 157 | { 158 | if (empty($filter)) { 159 | $this->logger->debug('OAuth2: No group specified in filter. All provided groups will be used.'); 160 | return true; 161 | } else { 162 | if (in_array($group, $filter)) { 163 | return true; 164 | } else { 165 | return false; 166 | } 167 | } 168 | } 169 | 170 | /** 171 | * Get external group ids 172 | * 173 | * A synchronization is done at login time, 174 | * the user will be member of those groups if they exists in the database 175 | * 176 | * @access public 177 | * @return string[] 178 | */ 179 | public function getExternalGroupIds() 180 | { 181 | $key = 'oauth2_key_groups'; 182 | 183 | $filteredGroups = array(); 184 | 185 | // Fixed custom groups 186 | $custom_groups = array(); 187 | $custom_groups_raw = $this->configModel->get('oauth2_custom_group'); 188 | if (!empty($custom_groups_raw)) { 189 | $custom_groups = explode(',', $custom_groups_raw); 190 | $custom_groups = array_map('trim', $custom_groups); 191 | } 192 | foreach ($custom_groups as $group) { 193 | $this->groupModel->getOrCreateExternalGroupId($group, $group); 194 | array_push($filteredGroups, $group); 195 | } 196 | 197 | 198 | if (empty($this->configModel->get($key))) { 199 | return $filteredGroups; 200 | } 201 | 202 | $groups = $this->getKey($key); 203 | 204 | if (empty($groups)) { 205 | $this->logger->debug('OAuth2: '.$this->getUsername().' has no groups'); 206 | return array(); 207 | } 208 | 209 | if(!is_array($groups)) { 210 | $groups = array($groups); 211 | } 212 | 213 | $groups = array_unique($groups); 214 | $this->logger->debug('OAuth2: '.$this->getUsername().' groups are '. join(',', $groups)); 215 | 216 | $groupFilter = array(); 217 | 218 | $confGroupFilter = $this->configModel->get('oauth2_key_group_filter'); 219 | if (!empty($confGroupFilter)) { 220 | $groupFilter = explode(',', $confGroupFilter); 221 | $groupFilter = array_map('trim', $groupFilter); 222 | } 223 | 224 | foreach ($groups as $group) { 225 | if ( $this->isGroupInFilter($group, $groupFilter)) { 226 | $this->groupModel->getOrCreateExternalGroupId($group, $group); 227 | array_push($filteredGroups, $group); 228 | } else { 229 | $this->logger->debug('OAuth2: '.$group.' will be ignored.'); 230 | } 231 | } 232 | 233 | return $filteredGroups; 234 | } 235 | 236 | /** 237 | * Return true if the account creation is allowed according to the settings 238 | * 239 | * @access public 240 | * @param array $profile 241 | * @return bool 242 | */ 243 | public function isAccountCreationAllowed(array $profile) 244 | { 245 | if ($this->isUserCreationAllowed()) { 246 | $domains = $this->configModel->get('oauth2_email_domains'); 247 | 248 | if (! empty($domains)) { 249 | return $this->validateDomainRestriction($profile, $domains); 250 | } 251 | 252 | return true; 253 | } 254 | 255 | return false; 256 | } 257 | 258 | /** 259 | * Validate domain restriction 260 | * 261 | * @access private 262 | * @param array $profile 263 | * @param string $domains 264 | * @return bool 265 | */ 266 | public function validateDomainRestriction(array $profile, $domains) 267 | { 268 | foreach (explode(',', $domains) as $domain) { 269 | $domain = trim($domain); 270 | 271 | if (strpos($profile['email'], $domain) > 0) { 272 | return true; 273 | } 274 | } 275 | 276 | return false; 277 | } 278 | 279 | protected function getKey($key) 280 | { 281 | if($this->configModel->get('oauth2_split_keys') == 1) { 282 | $key = explode('.', $this->configModel->get($key)); 283 | $value = $this->userData; 284 | foreach ($key as $k) { 285 | $value = $value[$k]; 286 | } 287 | return ! empty($key) && isset($value) ? $value : ''; 288 | } else { 289 | $key = $this->configModel->get($key); 290 | if(empty($key)) { 291 | return ''; 292 | } 293 | 294 | $value = $this->userData[$key]; 295 | return isset($value) ? $value : ''; 296 | } 297 | } 298 | } 299 | --------------------------------------------------------------------------------