Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
10 changes: 7 additions & 3 deletions core/Piwik.php
Original file line number Diff line number Diff line change
Expand Up @@ -292,10 +292,14 @@ public static function hasUserSuperUserAccessOrIsTheUser($theUser)
* Returns if the given user needs to confirm his password in UI and for certain API methods
*
* @param string $login
* @param string $passwordConfirmation
* @return bool
*/
public static function doesUserRequirePasswordConfirmation(string $login)
{
public static function doesUserRequirePasswordConfirmation(
string $login,
#[\SensitiveParameter]
string $passwordConfirmation = ''
) {
$requiresPasswordConfirmation = true;

/**
Expand All @@ -309,7 +313,7 @@ public static function doesUserRequirePasswordConfirmation(string $login)
* @param bool $requiresPasswordConfirmation Indicates if the password should be checked or not
* @param string $login Login of a user the password should be confirmed for
*/
Piwik::postEvent('Login.userRequiresPasswordConfirmation', [&$requiresPasswordConfirmation, $login]);
Piwik::postEvent('Login.userRequiresPasswordConfirmation', [&$requiresPasswordConfirmation, $login, $passwordConfirmation]);

return $requiresPasswordConfirmation;
}
Expand Down
2 changes: 1 addition & 1 deletion core/Plugin/API.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ protected function confirmCurrentUserPassword(
) {
$loginCurrentUser = Piwik::getCurrentUserLogin();

if (!Piwik::doesUserRequirePasswordConfirmation($loginCurrentUser)) {
if (!Piwik::doesUserRequirePasswordConfirmation($loginCurrentUser, $passwordConfirmation)) {
return; // password confirmation disabled for user
}

Expand Down
2 changes: 1 addition & 1 deletion plugins/CoreAdminHome/templates/generalSettings.twig
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,6 @@
</div>
{% endif %}

<div vue-entry="CorePluginsAdmin.PluginSettings" mode="admin"></div>
<div vue-entry="CorePluginsAdmin.PluginSettings" mode="admin" is-re-auth-enabled="true"></div>

{% endblock %}
39 changes: 39 additions & 0 deletions plugins/CorePluginsAdmin/Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,45 @@
return $view->render();
}

/**
* @return string
* @throws Exception
*/
public function reAuthSSO(): string
{
Piwik::checkUserHasSuperUserAccess();
$request = \Piwik\Request::fromRequest();
$reAuthToken = $request->getStringParameter("reAuthToken", '');
if (empty($reAuthToken)) {
throw new Exception('ReAuthToken is empty');
}
$url = '';
Piwik::postEvent('PasswordConfirmation.getReAuthURL', [&$url, $reAuthToken]);
if (empty($url)) {

Check failure on line 165 in plugins/CorePluginsAdmin/Controller.php

View workflow job for this annotation

GitHub Actions / PHPStan

Variable $url in empty() always exists and is always falsy.
throw new Exception('No ReAuth URL specified');
}

return json_encode(['url' => $url]);

Check failure on line 169 in plugins/CorePluginsAdmin/Controller.php

View workflow job for this annotation

GitHub Actions / PHPStan

Unreachable statement - code above always terminates.
}

/**
* @return string
* @throws Exception
*/
public function reAuthSSOStatus(): string
{
Piwik::checkUserHasSuperUserAccess();
$request = \Piwik\Request::fromRequest();
$reAuthToken = $request->getStringParameter("reAuthToken", '');
if (empty($reAuthToken)) {
throw new Exception('Invalid Token');
}
$status = 0;
Piwik::postEvent('PasswordConfirmation.reAuthSSOStatus', [&$status, $reAuthToken]);

return json_encode(['status' => $status]);
}

public function tagManagerTeaser()
{
$this->dieIfPluginsAdminIsDisabled();
Expand Down
140 changes: 106 additions & 34 deletions plugins/CorePluginsAdmin/vue/dist/CorePluginsAdmin.umd.js

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions plugins/CorePluginsAdmin/vue/dist/CorePluginsAdmin.umd.min.js

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@
</div>
</div>
<div class="modal-footer">
<a href=""
v-if="isReAuthEnabled"
class="modal-action btn"
style="margin-right: 1rem;"
@click="onClickReAuth($event)">
ReAuth via SSO</a>
<a
href=""
class="modal-action modal-close btn"
Expand All @@ -53,12 +59,14 @@

<script lang="ts">
import { defineComponent } from 'vue';
import { Matomo, AutoClearPassword } from 'CoreHome';
import { Matomo, AutoClearPassword, AjaxHelper } from 'CoreHome';
import Field from '../Field/Field.vue';
import KeyPressEvent = JQuery.KeyPressEvent;

const { $ } = window;

let refreshIntervalId = 0;

interface PasswordConfirmationState {
passwordConfirmation: string;
slotHasContent: boolean;
Expand All @@ -77,6 +85,11 @@ export default defineComponent({
type: String,
default: () => 'currentUserPassword',
},
isReAuthEnabled: {
type: Boolean,
required: false,
default: false,
},
},
data(): PasswordConfirmationState {
return {
Expand All @@ -95,8 +108,45 @@ export default defineComponent({
this.$emit('update:modelValue', false);
},
methods: {
onClickReAuth(event: MouseEvent) {
event.preventDefault();
// open a new Tab to reAuth
const token = `reAuth_${Math.random().toString(16).slice(2)}`;
AjaxHelper.fetch(
{ module: 'CorePluginsAdmin', action: 'reAuthSSO', reAuthToken: token },
).then((resp) => {
if (resp && resp.url) {
const newWindow = window.open(resp.url, '_blank');
if (newWindow) {
newWindow.focus();
}
// Also start calling an Ajax endpoint to check if reAuth successful
refreshIntervalId = setInterval(this.checkSSOStatus, 2000, token);
}
}).catch(() => {
console.log('error');
});
},
checkSSOStatus(token: string) {
AjaxHelper.fetch(
{ module: 'CorePluginsAdmin', action: 'reAuthSSOStatus', reAuthToken: token },
).then((response) => {
if (response && response.status === 1) {
const root = this.$refs.root as HTMLElement;
const $root = $(root);
$root.modal('close');
this.$emit('confirmed', token);
clearInterval(refreshIntervalId);
}
}).catch(() => {
clearInterval(refreshIntervalId);
});
},
onClickConfirm(event: MouseEvent) {
event.preventDefault();
if (refreshIntervalId) {
clearInterval(refreshIntervalId);
}
const root = this.$refs.root as HTMLElement;
const $root = $(root);
$root.modal('close');
Expand All @@ -105,6 +155,9 @@ export default defineComponent({
},
onClickCancel(event: MouseEvent) {
event.preventDefault();
if (refreshIntervalId) {
clearInterval(refreshIntervalId);
}
const root = this.$refs.root as HTMLElement;
const $root = $(root);
$root.modal('close');
Expand Down Expand Up @@ -138,6 +191,15 @@ export default defineComponent({
},
},
computed: {
isReAuthPossibleM() {
const parameters = {
isAllowed: false,
};
Matomo.postEvent('CorePluginsAdmin.isReAuthPossible', parameters);
console.log(parameters, 'parameters');

return parameters.isAllowed;
},
requiresPasswordConfirmation() {
return !!Matomo.requiresPasswordConfirmation;
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
</div>
<PasswordConfirmation
v-model="showPasswordConfirmModal"
:is-re-auth-enabled="isReAuthEnabled"
@confirmed="confirmPassword"
/>
</div>
Expand Down Expand Up @@ -71,6 +72,11 @@ interface PluginSettingsState {
export default defineComponent({
props: {
mode: String,
isReAuthEnabled: {
type: Boolean,
required: false,
default: false,
},
},
components: {
PasswordConfirmation,
Expand Down
Loading