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());
+    }
+}

Reply via email to