Skip to content

Commit 67dbf3b

Browse files
committed
Merge branch 'master' of github.com:apereo/cas
# Conflicts: # core/cas-server-core-util-api/src/main/java/org/apereo/cas/util/http/HttpRequestUtils.java # support/cas-server-support-pm-webflow/src/test/java/org/apereo/cas/pm/web/flow/actions/PasswordChangeActionTests.java # support/cas-server-support-syncope-authentication/src/main/java/org/apereo/cas/syncope/pm/SyncopePasswordManagementService.java
2 parents 8be025f + 2f68b70 commit 67dbf3b

File tree

5 files changed

+43
-27
lines changed

5 files changed

+43
-27
lines changed

ci/tests/puppeteer/scenarios/pm-reset-password-syncope/script.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ const cas = require("../../cas.js");
5151
await cas.goto(page, link);
5252
await cas.sleep(2000);
5353

54+
await cas.assertInnerText(page, "#content h2", "Answer Security Questions");
55+
56+
await cas.type(page, "#q0", "Rome", true);
57+
await cas.pressEnter(page);
58+
await cas.waitForNavigation(page);
59+
await cas.sleep(2000);
5460
await cas.assertInnerText(page, "#pwdmain h3", `Hello, ${username}. You must change your password.`);
5561

5662
newPassword = await cas.randomWord();

ci/tests/puppeteer/scenarios/pm-reset-password-syncope/script.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
"--cas.authn.pm.reset.mail.text=${url}",
2828
"--cas.authn.pm.reset.mail.subject=Reset",
2929
"--cas.authn.pm.reset.mail.attribute-name=mail",
30-
"--cas.authn.pm.reset.security-questions-enabled=false",
3130

3231
"--cas.authn.pm.syncope.basic-auth-username=admin",
3332
"--cas.authn.pm.syncope.basic-auth-password=password",

ci/tests/syncope/run-syncope-server.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,8 @@ for i in {0..4}; do
261261
"username": '\""syncopepasschange${suffix}\""',
262262
"password": "Sync0pe",
263263
"mustChangePassword": true,
264+
"securityQuestion": "'"${SECURITY_QUESTION_KEY}"'",
265+
"securityAnswer": "Rome",
264266
"plainAttrs": [
265267
{
266268
"schema": "email",

core/cas-server-core-util-api/src/main/java/org/apereo/cas/util/http/HttpRequestUtils.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,17 @@ public class HttpRequestUtils {
5252
result.setHeaders(response.getHeaders());
5353
result.setLocale(ObjectUtils.getIfNull(response.getLocale(), Locale.getDefault()));
5454
result.setVersion(ObjectUtils.getIfNull(response.getVersion(), HttpVersion.HTTP_1_1));
55-
val output = new ByteArrayOutputStream();
56-
if (response.getEntity() != null) {
57-
response.getEntity().writeTo(output);
58-
val contentTypeHeader = response.getFirstHeader(HttpHeaders.CONTENT_TYPE);
59-
val contentType = contentTypeHeader != null ? contentTypeHeader.getValue() : ContentType.APPLICATION_JSON.getMimeType();
60-
result.setEntity(new ByteArrayEntity(output.toByteArray(), ContentType.parseLenient(contentType)));
55+
56+
val entity = response.getEntity();
57+
if (entity != null) {
58+
try (val output = new ByteArrayOutputStream()) {
59+
entity.writeTo(output);
60+
val contentTypeHeader = response.getFirstHeader(HttpHeaders.CONTENT_TYPE);
61+
val contentType = contentTypeHeader != null ? contentTypeHeader.getValue() : ContentType.APPLICATION_JSON.getMimeType();
62+
result.setEntity(new ByteArrayEntity(output.toByteArray(), ContentType.parseLenient(contentType)));
63+
}
6164
}
65+
6266
return result;
6367
};
6468

support/cas-server-support-syncope-authentication/src/main/java/org/apereo/cas/syncope/pm/SyncopePasswordManagementService.java

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.apache.commons.lang3.StringUtils;
2020
import org.apache.commons.lang3.Strings;
2121
import org.apache.hc.core5.http.HttpEntityContainer;
22+
import org.apache.hc.core5.http.HttpResponse;
2223
import org.apache.hc.core5.http.HttpStatus;
2324
import org.apache.hc.core5.http.io.entity.EntityUtils;
2425
import org.springframework.http.HttpHeaders;
@@ -192,26 +193,30 @@ public boolean unlockAccount(final Credential credential) throws Throwable {
192193
}
193194

194195
@Override
195-
public boolean isAnswerValidForSecurityQuestion(final PasswordManagementQuery query, final String question,
196-
final String knownAnswer, final String givenAnswer) {
197-
val url = Strings.CI.appendIfMissing(
198-
SpringExpressionLanguageValueResolver.getInstance().resolve(
199-
casProperties.getAuthn().getPm().getSyncope().getUrl()),
200-
"/rest/users/verifySecurityAnswer");
201-
val exec = HttpExecutionRequest.builder()
202-
.method(HttpMethod.POST)
203-
.url(url)
204-
.basicAuthUsername(casProperties.getAuthn().getPm().getSyncope().getBasicAuthUsername())
205-
.basicAuthPassword(casProperties.getAuthn().getPm().getSyncope().getBasicAuthPassword())
206-
.headers(Map.of(
207-
SyncopeUtils.SYNCOPE_HEADER_DOMAIN, casProperties.getAuthn().getPm().getSyncope().getDomain(),
208-
HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE,
209-
HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE))
210-
.parameters(Map.of("username", query.getUsername()))
211-
.entity(givenAnswer)
212-
.build();
213-
val response = Objects.requireNonNull(HttpUtils.execute(exec));
214-
return org.springframework.http.HttpStatus.resolve(response.getCode()).is2xxSuccessful();
196+
public boolean isAnswerValidForSecurityQuestion(final PasswordManagementQuery query, final String question, final String knownAnswer, final String givenAnswer) {
197+
HttpResponse response = null;
198+
try {
199+
val userSecurityAnswerUrl = Strings.CI.appendIfMissing(SpringExpressionLanguageValueResolver.getInstance()
200+
.resolve(casProperties.getAuthn().getPm().getSyncope().getUrl()),
201+
"/rest/users/verifySecurityAnswer");
202+
203+
LOGGER.debug("Check security answer validity for user [{}]", query.getUsername());
204+
val exec = HttpExecutionRequest.builder().method(HttpMethod.POST).url(userSecurityAnswerUrl)
205+
.basicAuthUsername(casProperties.getAuthn().getPm().getSyncope().getBasicAuthUsername())
206+
.basicAuthPassword(casProperties.getAuthn().getPm().getSyncope().getBasicAuthPassword())
207+
.headers(Map.of(
208+
SyncopeUtils.SYNCOPE_HEADER_DOMAIN, casProperties.getAuthn().getPm().getSyncope().getDomain(),
209+
HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE,
210+
HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE))
211+
.parameters(Map.of("username", query.getUsername()))
212+
.entity(givenAnswer)
213+
.maximumRetryAttempts(casProperties.getAuthn().getSyncope().getMaxRetryAttempts())
214+
.build();
215+
response = Objects.requireNonNull(HttpUtils.execute(exec));
216+
return org.springframework.http.HttpStatus.resolve(response.getCode()).is2xxSuccessful();
217+
} finally {
218+
HttpUtils.close(response);
219+
}
215220
}
216221

217222
protected String fetchSyncopeUserKey(final String username) {

0 commit comments

Comments
 (0)