This is an automated email from the ASF dual-hosted git repository.
enorman pushed a commit to branch master
in repository
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-starter-content.git
The following commit(s) were added to refs/heads/master by this push:
new da96f80 SLING-12971 move the o.a.s.auth.form login form to
o.a.s.starter.content (#15)
da96f80 is described below
commit da96f80515355682a40714e8e45fc73a85db3db3
Author: Eric Norman <[email protected]>
AuthorDate: Wed Oct 22 11:25:33 2025 -0700
SLING-12971 move the o.a.s.auth.form login form to o.a.s.starter.content
(#15)
---
pom.xml | 11 +++
.../apache/sling/starter/login/models/Login.java | 85 ++++++++++++++++++++++
.../sling/starter/login/models/package-info.java | 21 ++++++
.../apps/sling/starter/home/login.html | 72 ++++++++++++++++++
.../sling/starter/login/models/LoginTest.java | 81 +++++++++++++++++++++
5 files changed, 270 insertions(+)
diff --git a/pom.xml b/pom.xml
index 2cabe80..07d9e6c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -87,6 +87,12 @@
<version>3.0.2</version>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.auth.core</artifactId>
+ <version>2.0.2</version>
+ <scope>provided</scope>
+ </dependency>
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.models.api</artifactId>
@@ -145,6 +151,11 @@
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-params</artifactId>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>jackrabbit-jcr-commons</artifactId>
diff --git a/src/main/java/org/apache/sling/starter/login/models/Login.java
b/src/main/java/org/apache/sling/starter/login/models/Login.java
new file mode 100644
index 0000000..1ae4f1d
--- /dev/null
+++ b/src/main/java/org/apache/sling/starter/login/models/Login.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.starter.login.models;
+
+import org.apache.sling.api.SlingJakartaHttpServletRequest;
+import
org.apache.sling.auth.core.spi.AuthenticationHandler.FAILURE_REASON_CODES;
+import org.apache.sling.auth.core.spi.JakartaAuthenticationHandler;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.injectorspecific.SlingObject;
+
+/**
+ * Model to assist rendering the custom login page
+ */
+@Model(adaptables = SlingJakartaHttpServletRequest.class)
+public class Login {
+
+ @SlingObject
+ protected SlingJakartaHttpServletRequest request;
+
+ /**
+ * Return the resource path to go to after login is successful
+ * @return the resource path or null
+ */
+ public String getResource() {
+ return request.getParameter("resource");
+ }
+
+ /**
+ * Returns an informational message according to the value provided in the
+ * <code>j_reason_code</code> request parameter. Supported reasons are
invalid
+ * credentials and session timeout.
+ *
+ * @return The "translated" reason to render the login form or an empty
string
+ * if there is no specific reason
+ */
+ public String getReason() {
+ String reason = null;
+ String jReasonCode =
request.getParameter(JakartaAuthenticationHandler.FAILURE_REASON_CODE);
+ if (jReasonCode != null && !jReasonCode.isEmpty()) {
+ FAILURE_REASON_CODES reasonCode;
+ try {
+ reasonCode = FAILURE_REASON_CODES.valueOf(jReasonCode);
+ } catch (IllegalArgumentException iae) {
+ reasonCode = FAILURE_REASON_CODES.UNKNOWN;
+ }
+
+ switch (reasonCode) {
+ case ACCOUNT_LOCKED:
+ reason = "Account is locked";
+ break;
+ case ACCOUNT_NOT_FOUND:
+ reason = "Account was not found";
+ break;
+ case PASSWORD_EXPIRED:
+ reason = "Password expired";
+ break;
+ case PASSWORD_EXPIRED_AND_NEW_PASSWORD_IN_HISTORY:
+ reason = "Password expired and new password found in
password history";
+ break;
+ case UNKNOWN, INVALID_LOGIN:
+ default:
+ reason = "User name and password do not match";
+ break;
+ }
+ }
+
+ return reason;
+ }
+}
diff --git
a/src/main/java/org/apache/sling/starter/login/models/package-info.java
b/src/main/java/org/apache/sling/starter/login/models/package-info.java
new file mode 100644
index 0000000..b52ce46
--- /dev/null
+++ b/src/main/java/org/apache/sling/starter/login/models/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
[email protected]("1.0.0")
+package org.apache.sling.starter.login.models;
diff --git
a/src/main/resources/initial-content/apps/sling/starter/home/login.html
b/src/main/resources/initial-content/apps/sling/starter/home/login.html
new file mode 100644
index 0000000..26498f5
--- /dev/null
+++ b/src/main/resources/initial-content/apps/sling/starter/home/login.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<html lang="en">
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+ <head>
+ <meta charset="utf-8" />
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
+ <title>Login to Apache Sling</title>
+ <link href="${request.contextPath}/starter/css/bundle.css"
rel="stylesheet" />
+ </head>
+ <body data-sly-use.p="org.apache.sling.starter.login.models.Login">
+ <div class="Grid Fit-Medium Home-Grid">
+ <div class="Gradient"></div>
+ <header class="Cell Medium-35 Large-25 Align-Center Logos">
+ <a href="https://sling.apache.org" target="_blank"
rel="noopener" id="sling-logo" title="Visit the Apache Sling website">
+ <img src="${request.contextPath}/starter/img/sling-logo.svg"
alt="Apache Sling Logo"/>
+ </a>
+ <a href="https://apache.org" target="_blank" rel="noopener"
id="asf-logo" title="Visit the Apache Software Foundation website">
+ <img src="${request.contextPath}/starter/img/asf-logo.svg"
alt="Apache Software Foundation Logo"/>
+ </a>
+ </header>
+ <div class="Cell Align-Center Main-Content">
+ <div class="Grid">
+ <section class="Cell Medium-35">
+ <h3>Login:</h3>
+ <form id="loginform" method="POST"
action="${request.contextPath}/j_security_check" enctype="multipart/form-data"
accept-charset="UTF-8">
+ <input type="hidden" name="_charset_"
value="UTF-8" />
+ <input type="hidden" name="resource"
value="${p.resource}" />
+ <div id="error">
+ <p>${p.reason}</p>
+ </div>
+ <div>
+ <label for="j_username"
accesskey="u">Username:</label>
+ </div>
+ <div>
+ <input id="j_username" name="j_username"
type="text" autofocus/>
+ </div>
+ <div>
+ <label for="j_password"
accesskey="p">Password:</label>
+ </div>
+ <div>
+ <input id="j_password" name="j_password"
type="password" />
+ </div>
+ <div class="buttongroup">
+ <button id="login" class="form-button"
type="submit">Login</button>
+ </div>
+ </form>
+ </section>
+ <div class="Cell Medium-65">
+ </div>
+ </div>
+ </div>
+ </div>
+ </body>
+</html>
diff --git a/src/test/java/org/apache/sling/starter/login/models/LoginTest.java
b/src/test/java/org/apache/sling/starter/login/models/LoginTest.java
new file mode 100644
index 0000000..7fd6630
--- /dev/null
+++ b/src/test/java/org/apache/sling/starter/login/models/LoginTest.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.starter.login.models;
+
+import java.util.stream.Stream;
+
+import org.apache.sling.api.SlingJakartaHttpServletRequest;
+import
org.apache.sling.auth.core.spi.AuthenticationHandler.FAILURE_REASON_CODES;
+import org.apache.sling.auth.core.spi.JakartaAuthenticationHandler;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.mockito.Mockito;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ *
+ */
+class LoginTest {
+
+ private Login login;
+
+ @BeforeEach
+ protected void before() {
+ login = new Login();
+ login.request = Mockito.mock(SlingJakartaHttpServletRequest.class);
+ }
+
+ /**
+ * Test method for {@link
org.apache.sling.starter.login.models.Login#getResource()}.
+ */
+ @Test
+ void testGetResource() {
+
Mockito.when(login.request.getParameter("resource")).thenReturn("/myresource1");
+ assertEquals("/myresource1", login.getResource());
+ }
+
+ protected static Stream<Arguments> testGetReasonArgs() {
+ return Stream.of(
+ Arguments.of(null, null),
+ Arguments.of("", null),
+ Arguments.of(FAILURE_REASON_CODES.ACCOUNT_LOCKED.name(),
"Account is locked"),
+ Arguments.of(FAILURE_REASON_CODES.ACCOUNT_NOT_FOUND.name(),
"Account was not found"),
+ Arguments.of(FAILURE_REASON_CODES.PASSWORD_EXPIRED.name(),
"Password expired"),
+ Arguments.of(
+
FAILURE_REASON_CODES.PASSWORD_EXPIRED_AND_NEW_PASSWORD_IN_HISTORY.name(),
+ "Password expired and new password found in password
history"),
+ Arguments.of(FAILURE_REASON_CODES.UNKNOWN.name(), "User name
and password do not match"),
+ Arguments.of(FAILURE_REASON_CODES.INVALID_LOGIN.name(), "User
name and password do not match"),
+ Arguments.of("other", "User name and password do not match"));
+ }
+ /**
+ * Test method for {@link
org.apache.sling.starter.login.models.Login#getReason()}.
+ */
+ @ParameterizedTest
+ @MethodSource("testGetReasonArgs")
+ void testGetReason(String reasonCode, String expectedMsg) {
+
Mockito.when(login.request.getParameter(JakartaAuthenticationHandler.FAILURE_REASON_CODE))
+ .thenReturn(reasonCode);
+ assertEquals(expectedMsg, login.getReason());
+ }
+}