Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions lib/Controller/ApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use OCA\UserOIDC\Db\UserMapper;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
use OCP\AppFramework\Http\DataResponse;
use OCP\Files\IRootFolder;
use OCP\Files\NotPermittedException;
Expand All @@ -30,15 +31,14 @@ public function __construct(
}

/**
* @NoCSRFRequired
*
* @param int $providerId
* @param string $userId
* @param string|null $displayName
* @param string|null $email
* @param string|null $quota
* @return DataResponse
*/
#[NoCSRFRequired]
public function createUser(int $providerId, string $userId, ?string $displayName = null,
?string $email = null, ?string $quota = null): DataResponse {
$backendUser = $this->userMapper->getOrCreate($providerId, $userId);
Expand Down Expand Up @@ -71,11 +71,10 @@ public function createUser(int $providerId, string $userId, ?string $displayName
}

/**
* @NoCSRFRequired
*
* @param string $userId
* @return DataResponse
*/
#[NoCSRFRequired]
public function deleteUser(string $userId): DataResponse {
$user = $this->userManager->get($userId);
if (is_null($user) || $user->getBackendClassName() !== Application::APP_ID) {
Expand Down
28 changes: 14 additions & 14 deletions lib/Controller/Id4meController.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\BruteForceProtection;
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
use OCP\AppFramework\Http\Attribute\PublicPage;
use OCP\AppFramework\Http\Attribute\UseSession;
use OCP\AppFramework\Http\JSONResponse;
use OCP\AppFramework\Http\RedirectResponse;
use OCP\AppFramework\Http\TemplateResponse;
Expand Down Expand Up @@ -71,11 +75,9 @@ public function __construct(
$this->id4me = new Service($clientHelper);
}

/**
* @PublicPage
* @NoCSRFRequired
* @UseSession
*/
#[PublicPage]
#[NoCSRFRequired]
#[UseSession]
public function showLogin() {
if (!$this->id4MeService->getID4ME()) {
$message = $this->l10n->t('ID4Me is disabled');
Expand All @@ -94,13 +96,12 @@ public function showLogin() {
}

/**
* @PublicPage
* @UseSession
* @BruteForceProtection(action=userOidcId4MeLogin)
*
* @param string $domain
* @return RedirectResponse|TemplateResponse
*/
#[PublicPage]
#[UseSession]
#[BruteForceProtection(action: 'userOidcId4MeLogin')]
public function login(string $domain) {
if (!$this->id4MeService->getID4ME()) {
$message = $this->l10n->t('ID4Me is disabled');
Expand Down Expand Up @@ -164,17 +165,16 @@ private function registerClient(string $authorityName, OpenIdConfig $openIdConfi
}

/**
* @PublicPage
* @NoCSRFRequired
* @UseSession
* @BruteForceProtection(action=userOidcId4MeCode)
*
* @param string $state
* @param string $code
* @param string $scope
* @return JSONResponse|RedirectResponse|TemplateResponse
* @throws \Exception
*/
#[PublicPage]
#[NoCSRFRequired]
#[UseSession]
#[BruteForceProtection(action: 'userOidcId4MeCode')]
public function code(string $state = '', string $code = '', string $scope = '') {
if (!$this->id4MeService->getID4ME()) {
$message = $this->l10n->t('ID4Me is disabled');
Expand Down
39 changes: 20 additions & 19 deletions lib/Controller/LoginController.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\BruteForceProtection;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
use OCP\AppFramework\Http\Attribute\PublicPage;
use OCP\AppFramework\Http\Attribute\UseSession;
use OCP\AppFramework\Http\DataDisplayResponse;
use OCP\AppFramework\Http\JSONResponse;
use OCP\AppFramework\Http\RedirectResponse;
Expand Down Expand Up @@ -128,15 +133,14 @@ private function getRedirectResponse(?string $redirectUrl = null): RedirectRespo
}

/**
* @PublicPage
* @NoCSRFRequired
* @UseSession
* @BruteForceProtection(action=userOidcLogin)
*
* @param int $providerId
* @param string|null $redirectUrl
* @return DataDisplayResponse|RedirectResponse|TemplateResponse
*/
#[PublicPage]
#[NoCSRFRequired]
#[UseSession]
#[BruteForceProtection(action: 'userOidcLogin')]
public function login(int $providerId, ?string $redirectUrl = null) {
if ($this->userSession->isLoggedIn()) {
return $this->getRedirectResponse($redirectUrl);
Expand Down Expand Up @@ -298,11 +302,6 @@ public function login(int $providerId, ?string $redirectUrl = null) {
}

/**
* @PublicPage
* @NoCSRFRequired
* @UseSession
* @BruteForceProtection(action=userOidcCode)
*
* @param string $state
* @param string $code
* @param string $scope
Expand All @@ -314,6 +313,10 @@ public function login(int $providerId, ?string $redirectUrl = null) {
* @throws SessionNotAvailableException
* @throws \JsonException
*/
#[PublicPage]
#[NoCSRFRequired]
#[UseSession]
#[BruteForceProtection(action: 'userOidcCode')]
public function code(string $state = '', string $code = '', string $scope = '', string $error = '', string $error_description = '') {
if (!$this->isSecure()) {
return $this->buildProtocolErrorResponse();
Expand Down Expand Up @@ -650,17 +653,16 @@ public function code(string $state = '', string $code = '', string $scope = '',
/**
* Endpoint called by NC to logout in the IdP before killing the current session
*
* @PublicPage
* @NoAdminRequired
* @NoCSRFRequired
* @UseSession
* @BruteForceProtection(action=userOidcSingleLogout)
*
* @return RedirectResponse|TemplateResponse
* @throws Exception
* @throws SessionNotAvailableException
* @throws \JsonException
*/
#[PublicPage]
#[NoAdminRequired]
#[NoCSRFRequired]
#[UseSession]
#[BruteForceProtection(action: 'userOidcSingleLogout')]
public function singleLogoutService() {
// TODO throttle in all failing cases
$oidcSystemConfig = $this->config->getSystemValue('user_oidc', []);
Expand Down Expand Up @@ -738,15 +740,14 @@ public function singleLogoutService() {
* which leads to the auth token that we can invalidate
* Implemented according to https://openid.net/specs/openid-connect-backchannel-1_0.html
*
* @PublicPage
* @NoCSRFRequired
*
* @param string $providerIdentifier
* @param string $logout_token
* @return JSONResponse
* @throws Exception
* @throws \JsonException
*/
#[PublicPage]
#[NoCSRFRequired]
public function backChannelLogout(string $providerIdentifier, string $logout_token = ''): JSONResponse {
// get the provider
$provider = $this->providerService->getProviderByIdentifier($providerIdentifier);
Expand Down
7 changes: 4 additions & 3 deletions lib/Controller/TimezoneController.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
namespace OCA\UserOIDC\Controller;

use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\Attribute\UseSession;
use OCP\AppFramework\Http\JSONResponse;
use OCP\IConfig;
use OCP\IRequest;
Expand All @@ -27,14 +29,13 @@ public function __construct(
}

/**
* @NoAdminRequired
* @UseSession
*
* @param string $timezone
* @param int $timezoneOffset
* @return JSONResponse
* @throws \OCP\PreConditionNotMetException
*/
#[NoAdminRequired]
#[UseSession]
public function setTimezone(string $timezone, int $timezoneOffset) {
$this->config->setUserValue($this->userId, 'core', 'timezone', $timezone);
$this->session->set('timezone', $timezoneOffset);
Expand Down
87 changes: 47 additions & 40 deletions src/components/AdminSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,40 +10,34 @@
<p>
{{ t('user_oidc', 'Allows users to authenticate via OpenID Connect providers.') }}
</p>
<p>
<NcCheckboxRadioSwitch
v-model="id4meState"
wrapper-element="div"
@update:model-value="onId4MeChange">
{{ t('user_oidc', 'Enable ID4me') }}
</NcCheckboxRadioSwitch>
</p>
<p class="line">
<NcCheckboxRadioSwitch
v-model="storeLoginTokenState"
wrapper-element="div"
@update:model-value="onStoreLoginTokenChange">
{{ t('user_oidc', 'Store login tokens') }}
</NcCheckboxRadioSwitch>
<NcButton variant="tertiary"
:title="t('user_oidc', 'This is needed if you are using other apps that want to use user_oidc\'s token exchange or simply get the login token')">
<template #icon>
<HelpCircleOutlineIcon />
</template>
</NcButton>
</p>
<div class="top-boxes">
<NcFormBox>
<NcFormBoxSwitch
v-model="id4meState"
@update:model-value="onId4MeChange">
{{ t('user_oidc', 'Enable ID4me') }}
</NcFormBoxSwitch>
<NcFormBoxSwitch
v-model="storeLoginTokenState"
@update:model-value="onStoreLoginTokenChange">
{{ t('user_oidc', 'Store login tokens') }}
</NcFormBoxSwitch>
</NcFormBox>
<NcNoteCard type="info">
{{ t('user_oidc', '"Store login tokens" is needed if you are using other apps that want to use user_oidc\'s token exchange or simply get the login token') }}
</NcNoteCard>
</div>
</div>
<div class="section">
<h2>
<h2 class="register-title">
{{ t('user_oidc', 'Registered Providers') }}
<NcActions>
<NcActionButton @click="showNewProvider=true">
<template #icon>
<PlusIcon :size="20" />
</template>
{{ t('user_oidc', 'Register new provider') }}
</NcActionButton>
</NcActions>
<NcButton variant="secondary"
:title="t('user_oidc', 'Register new provider')"
@click="showNewProvider = true">
<template #icon>
<PlusIcon :size="20" />
</template>
</NcButton>
</h2>

<NcModal v-if="showNewProvider"
Expand Down Expand Up @@ -133,20 +127,22 @@
</template>

<script>
import HelpCircleOutlineIcon from 'vue-material-design-icons/HelpCircleOutline.vue'
import PencilOutlineIcon from 'vue-material-design-icons/PencilOutline.vue'
import PlusIcon from 'vue-material-design-icons/Plus.vue'
import TrashCanOutlineIcon from 'vue-material-design-icons/TrashCanOutline.vue'

import axios from '@nextcloud/axios'
import { generateUrl } from '@nextcloud/router'
import { showError } from '@nextcloud/dialogs'
import NcActions from '@nextcloud/vue/components/NcActions'
import NcActionButton from '@nextcloud/vue/components/NcActionButton'
import NcModal from '@nextcloud/vue/components/NcModal'
import NcCheckboxRadioSwitch from '@nextcloud/vue/components/NcCheckboxRadioSwitch'
import NcButton from '@nextcloud/vue/components/NcButton'
import NcDialog from '@nextcloud/vue/components/NcDialog'
import NcFormBoxSwitch from '@nextcloud/vue/components/NcFormBoxSwitch'
import NcFormBox from '@nextcloud/vue/components/NcFormBox'
import NcNoteCard from '@nextcloud/vue/components/NcNoteCard'

import axios from '@nextcloud/axios'
import { generateUrl } from '@nextcloud/router'
import { showError } from '@nextcloud/dialogs'
import { confirmPassword } from '@nextcloud/password-confirmation'

import logger from '../logger.js'
Expand All @@ -159,13 +155,14 @@ export default {
NcActions,
NcActionButton,
NcModal,
NcCheckboxRadioSwitch,
NcButton,
NcFormBoxSwitch,
NcFormBox,
NcNoteCard,
PencilOutlineIcon,
TrashCanOutlineIcon,
NcDialog,
PlusIcon,
HelpCircleOutlineIcon,
},
props: {
initialId4MeState: {
Expand Down Expand Up @@ -339,16 +336,26 @@ export default {
}
</script>
<style lang="scss" scoped>
h2 .action-item {
vertical-align: middle;
h2.register-title {
margin-top: -2px;
display: flex;
align-items: center;
justify-content: start;
gap: 8px;
}

h3 {
font-weight: bold;
padding-bottom: 12px;
}

.top-boxes {
display: flex;
flex-direction: column;
gap: 8px;
max-width: 900px;
}

.line {
display: flex;
}
Expand Down
Loading