Skip to content

Commit 9e9d48d

Browse files
committed
support invalid password for keycloak v2
1 parent 148bb41 commit 9e9d48d

File tree

3 files changed

+198
-8
lines changed

3 files changed

+198
-8
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
<!DOCTYPE html>
2+
<html class="login-pf" lang="en">
3+
4+
<head>
5+
<meta charset="utf-8">
6+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
7+
<meta name="robots" content="noindex, nofollow">
8+
<meta name="color-scheme" content="light dark">
9+
<meta name="viewport" content="width=device-width, initial-scale=1">
10+
11+
<title>Sign in to internal</title>
12+
<link rel="icon" href="/resources/kb6gy/login/keycloak.v2/img/favicon.ico" />
13+
<link href="/resources/kb6gy/common/keycloak/vendor/patternfly-v5/patternfly.min.css" rel="stylesheet" />
14+
<link href="/resources/kb6gy/common/keycloak/vendor/patternfly-v5/patternfly-addons.css" rel="stylesheet" />
15+
<link href="/resources/kb6gy/login/keycloak.v2/css/styles.css" rel="stylesheet" />
16+
<script type="importmap">
17+
{
18+
"imports": {
19+
"rfc4648": "/resources/kb6gy/common/keycloak/vendor/rfc4648/rfc4648.js"
20+
}
21+
}
22+
</script>
23+
<script type="module" async blocking="render">
24+
const DARK_MODE_CLASS = "pf-v5-theme-dark";
25+
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
26+
27+
updateDarkMode(mediaQuery.matches);
28+
mediaQuery.addEventListener("change", (event) => updateDarkMode(event.matches));
29+
30+
function updateDarkMode(isEnabled) {
31+
const { classList } = document.documentElement;
32+
33+
if (isEnabled) {
34+
classList.add(DARK_MODE_CLASS);
35+
} else {
36+
classList.remove(DARK_MODE_CLASS);
37+
}
38+
}
39+
</script>
40+
<script type="module" src="/resources/kb6gy/login/keycloak.v2/js/passwordVisibility.js"></script>
41+
<script type="module">
42+
import { startSessionPolling } from "/resources/kb6gy/login/keycloak.v2/js/authChecker.js";
43+
44+
startSessionPolling(
45+
"/realms/internal/login-actions/restart?client_id=urn%3Aamazon%3Awebservices&tab_id=tabId&client_data=clientData&skip_logout=true"
46+
);
47+
</script>
48+
<script type="module">
49+
import { checkAuthSession } from "/resources/kb6gy/login/keycloak.v2/js/authChecker.js";
50+
51+
checkAuthSession(
52+
"sessionId"
53+
);
54+
</script>
55+
<script>
56+
// Workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=1404468
57+
const isFirefox = true;
58+
</script>
59+
<SCRIPT> if (typeof history.replaceState === 'function') { history.replaceState({}, "some title", "https://my.domain/realms/internal/login-actions/authenticate?execution=uuid&client_id=urn%3Aamazon%3Awebservices&tab_id=tabId&client_data=clientData"); }</SCRIPT></head>
60+
61+
<body id="keycloak-bg" class="">
62+
<div class="pf-v5-c-login">
63+
<div class="pf-v5-c-login__container">
64+
<header id="kc-header" class="pf-v5-c-login__header">
65+
<div id="kc-header-wrapper"
66+
class="pf-v5-c-brand">internal</div>
67+
</header>
68+
<main class="pf-v5-c-login__main">
69+
<div class="pf-v5-c-login__main-header">
70+
<h1 class="pf-v5-c-title pf-m-3xl" id="kc-page-title"><!-- template: login.ftl -->
71+
72+
Sign in to your account
73+
74+
</h1>
75+
</div>
76+
<div class="pf-v5-c-login__main-body">
77+
78+
79+
<!-- template: login.ftl -->
80+
81+
<div id="kc-form">
82+
<div id="kc-form-wrapper">
83+
<form id="kc-form-login" class="pf-v5-c-form" onsubmit="login.disabled = true; return true;" action="https://my.domain/realms/internal/login-actions/authenticate?session_code=sessionId&amp;execution=uuid&amp;client_id=urn%3Aamazon%3Awebservices&amp;tab_id=tabId&amp;client_data=clientData" method="post" novalidate="novalidate">
84+
85+
<div class="pf-v5-c-form__group">
86+
<div class="pf-v5-c-form__label">
87+
<label for="username" class="pf-v5-c-form__label">
88+
<span class="pf-v5-c-form__label-text">
89+
Username or email
90+
91+
</span>
92+
</label>
93+
</div>
94+
95+
<span class="pf-v5-c-form-control pf-m-error">
96+
<input id="username" name="username" value="aorlovskiy" type="text" autocomplete="username" autofocus
97+
aria-invalid="true"/>
98+
<span class="pf-v5-c-form-control__utilities">
99+
<span class="pf-v5-c-form-control__icon pf-m-status">
100+
<i class="fas fa-exclamation-circle" aria-hidden="true"></i>
101+
</span>
102+
</span>
103+
</span>
104+
105+
<div id="input-error-container-username">
106+
<div class="pf-v5-c-form__helper-text" aria-live="polite">
107+
<div class="pf-v5-c-helper-text">
108+
<div class="pf-v5-c-helper-text__item pf-m-error" id="input-error-username">
109+
<span class="pf-v5-c-helper-text__item-text pf-m-error kc-feedback-text">
110+
Invalid username or password.
111+
</span>
112+
</div>
113+
</div>
114+
</div>
115+
</div>
116+
</div>
117+
118+
119+
<div class="pf-v5-c-form__group">
120+
<div class="pf-v5-c-form__label">
121+
<label for="password" class="pf-v5-c-form__label">
122+
<span class="pf-v5-c-form__label-text">
123+
Password
124+
</span>
125+
</label>
126+
</div>
127+
128+
<div class="pf-v5-c-input-group">
129+
<div class="pf-v5-c-input-group__item pf-m-fill">
130+
<span class="pf-v5-c-form-control ">
131+
<input id="password" name="password" value="" type="password" autocomplete="current-password"
132+
aria-invalid=""/>
133+
</span>
134+
</div>
135+
<div class="pf-v5-c-input-group__item">
136+
<button class="pf-v5-c-button pf-m-control" type="button" aria-label="Show password"
137+
aria-controls="password" data-password-toggle
138+
data-icon-show="fa-eye fas" data-icon-hide="fa-eye-slash fas"
139+
data-label-show="Show password" data-label-hide="Hide password">
140+
<i class="fa-eye fas" aria-hidden="true"></i>
141+
</button>
142+
</div>
143+
</div>
144+
145+
<div id="input-error-container-password">
146+
</div>
147+
</div>
148+
149+
150+
<div class="pf-v5-c-form__group">
151+
</div>
152+
153+
<input type="hidden" id="id-hidden-input" name="credentialId" />
154+
<div class="pf-v5-c-form__group">
155+
<div class="pf-v5-c-form__actions">
156+
<button class="pf-v5-c-button pf-m-primary pf-m-block " name="login" id="kc-login" type="submit">Sign In</button>
157+
</div>
158+
</div>
159+
</form>
160+
</div>
161+
</div>
162+
163+
164+
165+
</div>
166+
<div class="pf-v5-c-login__main-footer">
167+
<!-- template: login.ftl -->
168+
169+
170+
</div>
171+
</main>
172+
173+
</div>
174+
</div>
175+
</html>

pkg/provider/keycloak/keycloak.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,11 @@ type Client struct {
3232
authErrorValidator *authErrorValidator
3333
}
3434

35-
const (
36-
DefaultAuthErrorElement = "span#input-error"
37-
DefaultAuthErrorMessage = "Invalid username or password."
35+
var (
36+
defaultAuthErrorElementV1 = "span#input-error"
37+
defaultAuthErrorElementV2 = "div#input-error-username"
38+
DefaultAuthErrorElement = fmt.Sprintf("%s, %s", defaultAuthErrorElementV1, defaultAuthErrorElementV2)
39+
DefaultAuthErrorMessage = "Invalid username or password."
3840
)
3941

4042
type authErrorValidator struct {

pkg/provider/keycloak/keycloak_test.go

+18-5
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ func TestClient_CustomizeAuthErrorValidator_CustomSetup(t *testing.T) {
303303
require.Equal(t, authErrorValidator.httpMessageRE.String(), ErrMessage1+"|"+ErrMessage2)
304304
require.Equal(t, authErrorValidator.httpElement, httpElement)
305305
}
306+
306307
func TestClient_passwordValid_DefaultValidator(t *testing.T) {
307308
// Test with the default auth error message and the default HTTP element
308309
idpAccount := cfg.IDPAccount{
@@ -312,13 +313,25 @@ func TestClient_passwordValid_DefaultValidator(t *testing.T) {
312313
authErrorValidator, err := CustomizeAuthErrorValidator(&idpAccount)
313314
require.Nil(t, err)
314315

315-
data, err := os.ReadFile("example/authError-invalidPassword.html")
316-
require.Nil(t, err)
316+
tCases := []struct {
317+
name string
318+
file string
319+
}{
320+
{name: "v1", file: "example/authError-invalidPassword.html"},
321+
{name: "v2", file: "example/authError-invalidPassword-v2.html"},
322+
}
317323

318-
doc, err := goquery.NewDocumentFromReader(bytes.NewReader(data))
319-
require.Nil(t, err)
324+
for _, tc := range tCases {
325+
t.Run(tc.name, func(t *testing.T) {
326+
data, err := os.ReadFile(tc.file)
327+
require.Nil(t, err)
320328

321-
require.Equal(t, passwordValid(doc, authErrorValidator), false)
329+
doc, err := goquery.NewDocumentFromReader(bytes.NewReader(data))
330+
require.Nil(t, err)
331+
332+
require.Equal(t, passwordValid(doc, authErrorValidator), false)
333+
})
334+
}
322335
}
323336

324337
func TestClient_passwordValid_CustomValidator(t *testing.T) {

0 commit comments

Comments
 (0)