Skip to content
This repository was archived by the owner on Sep 19, 2022. It is now read-only.

Commit 8bb43bc

Browse files
committed
feat: new privacyIDEA template
BREAKING CHANGE: requires cesnet/simplesamlphp-module-privacyidea v5
1 parent b9f2c93 commit 8bb43bc

File tree

5 files changed

+104
-90
lines changed

5 files changed

+104
-90
lines changed

composer.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,5 +62,8 @@
6262
},
6363
"require-dev": {
6464
"symplify/easy-coding-standard": "^10.0"
65+
},
66+
"suggest": {
67+
"cesnet/simplesamlphp-module-privacyidea": "included privacyIDEA template is for this module"
6568
}
6669
}

dictionaries/privacyidea.definition.json

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,8 @@
77
"en": "The service you are trying to access has requested authentication using multiple factors. Use one of your registered additional authentication token using the buttons below.",
88
"cs": "Služba ke které přistupujete vyžádala vícefaktorovout autentizaci. Použijte jednu z vašich zaregistrovaných metod kliknutím na jedno z tlačítek nížě."
99
},
10-
"otp": {
11-
"en": "Security code",
12-
"cs": "Bezpečnostní kód"
13-
},
1410
"otp_help": {
1511
"en": "Enter the 6 digit one time password from the smartphone application.",
1612
"cs": "Vložte jednorázový kód, například z TOTP aplikace."
17-
},
18-
"otp_submit_btn": {
19-
"en": "Submit",
20-
"cs": "Potvrdit"
21-
},
22-
"webauthn": {
23-
"en": "Web Authentication",
24-
"cs": "Web Authentication"
25-
},
26-
"webauthn_btn": {
27-
"en": "Trigger authentication",
28-
"cs": "Spustit autentizaci"
2913
}
3014
}

themes/perun/privacyidea/LoginForm.php

Lines changed: 73 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,9 @@
44

55
$this->data['u2fAvailable'] = !empty($this->data['u2fSignRequest']);
66
$this->data['webauthnAvailable'] = !empty($this->data['webAuthnSignRequest']);
7-
$this->data['pushAvailable'] = $this->data['pushAvailable'] ?? false;
8-
97
$this->data['mode'] = ($this->data['mode'] ?? null) ?: 'otp';
108
$this->data['noAlternatives'] = true;
11-
foreach (['webauthn', 'otp', 'push', 'u2f'] as $mode) {
9+
foreach (['otp', 'push', 'u2f', 'webauthn'] as $mode) {
1210
if ($mode !== $this->data['mode'] && $this->data[$mode . 'Available']) {
1311
$this->data['noAlternatives'] = false;
1412
break;
@@ -25,8 +23,16 @@
2523
}
2624

2725
// Set the right text shown in otp/pass field(s)
28-
$otpHint = $this->data['otpFieldHint'] ?? $this->t('{privacyidea:privacyidea:otp}');
29-
$passHint = $this->data['passFieldHint'] ?? $this->t('{privacyidea:privacyidea:password}');
26+
if (isset($this->data['otpFieldHint'])) {
27+
$otpHint = $this->data['otpFieldHint'];
28+
} else {
29+
$otpHint = $this->t('{privacyidea:privacyidea:otp}');
30+
}
31+
if (isset($this->data['passFieldHint'])) {
32+
$passHint = $this->data['passFieldHint'];
33+
} else {
34+
$passHint = $this->t('{privacyidea:privacyidea:password}');
35+
}
3036

3137
$this->data['header'] = $this->t('{privacyidea:privacyidea:login_title_challenge}');
3238

@@ -40,20 +46,24 @@
4046
$this->data['head'] .= '<link rel="stylesheet" href="'
4147
. htmlspecialchars(Module::getModuleUrl('privacyidea/css/loginform.css'), ENT_QUOTES)
4248
. '" media="screen" />';
49+
$this->data['head'] .= '<link rel="stylesheet" href="'
50+
. htmlspecialchars(Module::getModuleUrl('perun/res/css/privacyidea.css'), ENT_QUOTES)
51+
. '" media="screen" />';
4352

4453
$this->includeAtTemplateBase('includes/header.php');
4554

4655
// Prepare error case to show it in UI if needed
4756
if (null !== $this->data['errorCode']) {
4857
?>
58+
4959
<div class="alert alert-dismissable alert-danger" role="alert">
50-
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
60+
<button type="button" class="close" data-dismiss="alert" aria-label="<?php echo $this->t('{perun:privacyidea:close}'); ?>">
5161
<span aria-hidden="true">&times;</span>
5262
</button>
5363
<h2 class="alert-heading"><?php echo $this->t('{login:error_header}'); ?></h2>
5464
<p>
55-
<?php
56-
echo htmlspecialchars(
65+
<?php
66+
echo htmlspecialchars(
5767
sprintf('%s%s: %s', $this->t(
5868
'{privacyidea:privacyidea:error}'
5969
), $this->data['errorCode'] ? (' ' . $this->data['errorCode']) : '', $this->data['errorMessage'])
@@ -64,61 +74,81 @@
6474
<?php
6575
} // end of errorcode
6676
?>
77+
6778
<p><?php echo $this->t('{perun:privacyidea:info_text}'); ?></p>
6879
<form action="FormReceiver.php" method="POST" id="piLoginForm" name="piLoginForm" class="loginForm">
6980
<div class="row">
7081
<?php if ($this->data['webauthnAvailable']) { ?>
71-
<div class="<?php echo (!$this->data['noAlternatives']) ? 'col-md-6' : 'col-sm-12'; ?>">
72-
<h2><?php echo $this->t('{perun:privacyidea:webauthn}'); ?></h2>
73-
<div>
74-
<button id="useWebAuthnButton" name="useWebAuthnButton" class="btn btn-primary btn-block text-nowrap" type="button"><?php echo $this->t('{perun:privacyidea:webauthn_btn}'); ?></button>
75-
</div>
76-
<div id="message" role="alert">
77-
<?php
82+
<div class="col-md-6">
83+
<h2><?php echo $this->t('{privacyidea:privacyidea:webauthn}'); ?></h2>
84+
<p id="message" role="alert"><?php
7885
$messageOverride = $this->data['messageOverride'] ?? null;
7986
if (null === $messageOverride || is_string($messageOverride)) {
8087
echo htmlspecialchars($messageOverride ?? $this->data['message'] ?? '', ENT_QUOTES);
8188
} elseif (is_callable($messageOverride)) {
8289
echo call_user_func($messageOverride, $this->data['message'] ?? '');
8390
}
84-
?>
85-
</div>
91+
?></p>
92+
<p>
93+
<button id="useWebAuthnButton" name="useWebAuthnButton" class="btn btn-primary btn-s" type="button">
94+
<span><?php echo $this->t('{privacyidea:privacyidea:webauthn}'); ?></span>
95+
</button>
96+
</p>
8697
</div>
8798
<?php } ?>
8899

89100
<?php if ($this->data['otpAvailable'] ?? true) { ?>
90-
<div class="<?php echo (!$this->data['noAlternatives']) ? 'col-md-6' : 'col-sm-12'; ?>">
101+
<div class="col-md-6">
91102
<h2><?php echo $this->t('{privacyidea:privacyidea:otp}'); ?></h2>
92103
<p><?php echo $this->t('{perun:privacyidea:otp_help}'); ?></p>
93104
<div class="form-row">
94-
<div class="form-group col-sm-12 <?php echo (!$this->data['noAlternatives']) ? '' : 'col-md-6'; ?>">
95-
<label for="otp" class="sr-only"><?php echo $this->t('{perun:privacyidea:otp}'); ?></label>
96-
<input id="otp" name="otp" tabindex="1" value="" class="form-control" autocomplete="one-time-code" type="text" inputmode="numeric" pattern="[0-9]{6,}" required placeholder="<?php echo htmlspecialchars($otpHint, ENT_QUOTES); ?>"/>
105+
<div class="form-group col-sm-12 col-md-6">
106+
<label for="otp" class="sr-only"><?php echo $this->t('{privacyidea:privacyidea:otp}'); ?></label>
107+
<input id="otp" name="otp" tabindex="1" value="" class="form-control" autocomplete="one-time-code" type="text" inputmode="numeric" pattern="[0-9]{6,}" required placeholder="<?php echo htmlspecialchars($otpHint, ENT_QUOTES); ?>"<?php if ($this->data['noAlternatives']) {
108+
echo ' autofocus';
109+
} ?> />
97110
</div>
98-
<div class="form-group col-sm-12 <?php echo (!$this->data['noAlternatives']) ? '' : 'col-md-6'; ?>">
99-
<button id="submitButton" tabindex="1" class="btn btn-primary btn-block text-nowrap" type="submit" name="Submit"><?php echo htmlspecialchars($this->t('{perun:privacyidea:otp_submit_btn}'), ENT_QUOTES); ?></button>
111+
<div class="form-group col-sm-12 col-md-6">
112+
<button id="submitButton" tabindex="1" class="btn btn-primary btn-block text-nowrap" type="submit" name="Submit">
113+
<span><?php echo htmlspecialchars($this->t('{login:login_button}'), ENT_QUOTES); ?></span>
114+
</button>
100115
</div>
101116
</div>
102117
</div>
103118
<?php } ?>
104-
</div>
105119

106-
<!-- Undefined index is suppressed and the default is used for these values -->
107-
<input id="mode" type="hidden" name="mode" value="otp" data-preferred="<?php echo htmlspecialchars($this->data['mode'], ENT_QUOTES); ?>"/>
108-
<input id="pushAvailable" type="hidden" name="pushAvailable" value="<?php echo ($this->data['pushAvailable'] ?? false) ? 'true' : ''; ?>"/>
109-
<input id="otpAvailable" type="hidden" name="otpAvailable" value="<?php echo ($this->data['otpAvailable'] ?? true) ? 'true' : ''; ?>"/>
110-
<input id="webAuthnSignRequest" type="hidden" name="webAuthnSignRequest" value='<?php echo htmlspecialchars($this->data['webAuthnSignRequest'] ?? '', ENT_QUOTES); ?>'/>
111-
<input id="u2fSignRequest" type="hidden" name="u2fSignRequest" value='<?php echo htmlspecialchars($this->data['u2fSignRequest'] ?? '', ENT_QUOTES); ?>'/>
112-
<input id="modeChanged" type="hidden" name="modeChanged" value=""/>
113-
<input id="step" type="hidden" name="step" value="<?php echo htmlspecialchars(strval(($this->data['step'] ?? null) ?: 2), ENT_QUOTES); ?>"/>
114-
<input id="webAuthnSignResponse" type="hidden" name="webAuthnSignResponse" value=""/>
115-
<input id="u2fSignResponse" type="hidden" name="u2fSignResponse" value=""/>
116-
<input id="origin" type="hidden" name="origin" value=""/>
117-
<input id="loadCounter" type="hidden" name="loadCounter" value="<?php echo htmlspecialchars(strval(($this->data['loadCounter'] ?? null) ?: 1), ENT_QUOTES); ?>"/>
118-
119-
<!-- Additional input to persist the message -->
120-
<input type="hidden" name="message" value="<?php echo htmlspecialchars($this->data['message'] ?? '', ENT_QUOTES); ?>"/>
120+
<!-- Undefined index is suppressed and the default is used for these values -->
121+
<input id="mode" type="hidden" name="mode" value="otp"
122+
data-preferred="<?php echo htmlspecialchars($this->data['mode'], ENT_QUOTES); ?>"/>
123+
124+
<input id="pushAvailable" type="hidden" name="pushAvailable"
125+
value="<?php echo ($this->data['pushAvailable'] ?? false) ? 'true' : ''; ?>"/>
126+
127+
<input id="otpAvailable" type="hidden" name="otpAvailable"
128+
value="<?php echo ($this->data['otpAvailable'] ?? true) ? 'true' : ''; ?>"/>
129+
130+
<input id="webAuthnSignRequest" type="hidden" name="webAuthnSignRequest"
131+
value='<?php echo htmlspecialchars($this->data['webAuthnSignRequest'] ?? '', ENT_QUOTES); ?>'/>
132+
133+
<input id="u2fSignRequest" type="hidden" name="u2fSignRequest"
134+
value='<?php echo htmlspecialchars($this->data['u2fSignRequest'] ?? '', ENT_QUOTES); ?>'/>
135+
136+
<input id="modeChanged" type="hidden" name="modeChanged" value=""/>
137+
<input id="step" type="hidden" name="step"
138+
value="<?php echo htmlspecialchars(strval(($this->data['step'] ?? null) ?: 2), ENT_QUOTES); ?>"/>
139+
140+
<input id="webAuthnSignResponse" type="hidden" name="webAuthnSignResponse" value=""/>
141+
<input id="u2fSignResponse" type="hidden" name="u2fSignResponse" value=""/>
142+
<input id="origin" type="hidden" name="origin" value=""/>
143+
<input id="loadCounter" type="hidden" name="loadCounter"
144+
value="<?php echo htmlspecialchars(strval(($this->data['loadCounter'] ?? null) ?: 1), ENT_QUOTES); ?>"/>
145+
146+
<!-- Additional input to persist the message -->
147+
<input type="hidden" name="message"
148+
value="<?php echo htmlspecialchars($this->data['message'] ?? '', ENT_QUOTES); ?>"/>
149+
</div> <!-- row -->
121150
</form>
151+
122152
<script src="<?php echo htmlspecialchars(Module::getModuleUrl('privacyidea/js/pi-webauthn.js'), ENT_QUOTES); ?>">
123153
</script>
124154

@@ -151,8 +181,10 @@
151181
echo htmlspecialchars(json_encode($translations));
152182
?>">
153183

154-
<script src="<?php echo htmlspecialchars(Module::getModuleUrl('privacyidea/js/loginform.js'), ENT_QUOTES); ?>"></script>
155-
<script src="<?php echo htmlspecialchars(Module::getModuleUrl('perun/js/privacy-idea-loginform.js'), ENT_QUOTES); ?>"></script>
184+
<script src="<?php echo htmlspecialchars(Module::getModuleUrl('privacyidea/js/loginform.js'), ENT_QUOTES); ?>">
185+
</script>
186+
<script src="<?php echo htmlspecialchars(Module::getModuleUrl('perun/res/js/privacyidea.js'), ENT_QUOTES); ?>">
187+
</script>
156188

157189
<?php
158190
$this->includeAtTemplateBase('includes/footer.php');

www/res/css/privacyidea.css

Lines changed: 12 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,13 @@
1-
.message--common-error {
2-
margin-left: 18px;
3-
width: 520px;
4-
}
5-
6-
.btn-wrap {
7-
text-align: center;
8-
}
9-
10-
.alternate-btn {
11-
margin-top: 1rem;
12-
}
13-
14-
.identifier-shown {
15-
margin-bottom: 5rem;
16-
}
17-
18-
#otp {
19-
margin-top: 0;
20-
}
21-
22-
#submitButton {
23-
margin-top: 1rem;
24-
}
25-
26-
@media (max-width: 576px) {
27-
.col-12 {
28-
width: 100%;
29-
}
30-
31-
.col-offset-0 {
32-
margin-left: 1%;
33-
}
1+
html #useWebAuthnButton,
2+
html #usePushButton,
3+
html #useOTPButton,
4+
html #useU2FButton,
5+
html #submitButton {
6+
margin: 0;
7+
width: auto;
8+
}
9+
10+
html #otp {
11+
margin: 0;
12+
width: 100%;
3413
}

www/res/js/privacyidea.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// privacyIDEA - allow WebAuthn and OTP on one page
2+
document.addEventListener("DOMContentLoaded", () => {
3+
["otp", "submitButton"].forEach((id) => {
4+
const el = document.getElementById(id);
5+
if (el) {
6+
el.classList.remove("hidden");
7+
}
8+
});
9+
10+
const piLoginForm = document.getElementById("piLoginForm");
11+
if (piLoginForm) {
12+
piLoginForm.addEventListener("submit", () => {
13+
document.getElementById("mode").value = "otp";
14+
});
15+
}
16+
});

0 commit comments

Comments
 (0)