diff --git a/.gitignore b/.gitignore index ee75b2ffc..c2bd7acae 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,8 @@ #ignore patches **/patches + +# ignore enviroment related files +*.swp +/.vscode +/.idea +.DS_Store diff --git a/Java-base/sling-org-apache-sling-auth-core/Dockerfile b/Java-base/sling-org-apache-sling-auth-core/Dockerfile new file mode 100644 index 000000000..e208c4890 --- /dev/null +++ b/Java-base/sling-org-apache-sling-auth-core/Dockerfile @@ -0,0 +1,28 @@ +FROM ubuntu:22.04 + +RUN export DEBIAN_FRONTEND=noninteractive \ + && apt-get update \ + && apt-get install -y software-properties-common \ + && add-apt-repository ppa:deadsnakes/ppa \ + && apt-get update \ + && apt-get install -y \ + build-essential \ + git \ + vim \ + jq \ + && apt-get autoremove -y && apt-get clean -y && rm -rf /var/lib/apt/list/* + +RUN apt-get -y install sudo \ + openjdk-8-jdk \ + maven + +RUN bash -c "echo 2 | update-alternatives --config java" + +COPY src /workspace +WORKDIR /workspace + +RUN mvn install -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false + +RUN mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 + +ENV TZ=Asia/Seoul diff --git a/Java-base/sling-org-apache-sling-auth-core/src/CODE_OF_CONDUCT.md b/Java-base/sling-org-apache-sling-auth-core/src/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..0fa18e593 --- /dev/null +++ b/Java-base/sling-org-apache-sling-auth-core/src/CODE_OF_CONDUCT.md @@ -0,0 +1,22 @@ + +Apache Software Foundation Code of Conduct +==== + +Being an Apache project, Apache Sling adheres to the Apache Software Foundation's [Code of Conduct](https://www.apache.org/foundation/policies/conduct.html). diff --git a/Java-base/sling-org-apache-sling-auth-core/src/CONTRIBUTING.md b/Java-base/sling-org-apache-sling-auth-core/src/CONTRIBUTING.md new file mode 100644 index 000000000..ac82a1abe --- /dev/null +++ b/Java-base/sling-org-apache-sling-auth-core/src/CONTRIBUTING.md @@ -0,0 +1,24 @@ + +Contributing +==== + +Thanks for choosing to contribute! + +You will find all the necessary details about how you can do this at https://sling.apache.org/contributing.html. diff --git a/Java-base/sling-org-apache-sling-auth-core/src/Jenkinsfile b/Java-base/sling-org-apache-sling-auth-core/src/Jenkinsfile new file mode 100644 index 000000000..f5825190c --- /dev/null +++ b/Java-base/sling-org-apache-sling-auth-core/src/Jenkinsfile @@ -0,0 +1,20 @@ +/** + * 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. + */ + +slingOsgiBundleBuild() diff --git a/Java-base/sling-org-apache-sling-auth-core/src/LICENSE b/Java-base/sling-org-apache-sling-auth-core/src/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/Java-base/sling-org-apache-sling-auth-core/src/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. diff --git a/Java-base/sling-org-apache-sling-auth-core/src/README.md b/Java-base/sling-org-apache-sling-auth-core/src/README.md new file mode 100644 index 000000000..0376abd97 --- /dev/null +++ b/Java-base/sling-org-apache-sling-auth-core/src/README.md @@ -0,0 +1,9 @@ +[](https://sling.apache.org) + + [![Build Status](https://builds.apache.org/buildStatus/icon?job=Sling/sling-org-apache-sling-auth-core/master)](https://builds.apache.org/job/Sling/job/sling-org-apache-sling-auth-core/job/master) [![Test Status](https://img.shields.io/jenkins/t/https/builds.apache.org/job/Sling/job/sling-org-apache-sling-auth-core/job/master.svg)](https://builds.apache.org/job/Sling/job/sling-org-apache-sling-auth-core/job/master/test_results_analyzer/) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.apache.sling/org.apache.sling.auth.core/badge.svg)](https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22org.apache.sling%22%20a%3A%22org.apache.sling.auth.core%22) [![JavaDocs](https://www.javadoc.io/badge/org.apache.sling/org.apache.sling.auth.core.svg)](https://www.javadoc.io/doc/org.apache.sling/org.apache.sling.auth.core) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0) [![auth](https://sling.apache.org/badges/group-auth.svg)](https://github.com/apache/sling-aggregator/blob/master/docs/groups/auth.md) + +# Apache Sling Authentication Service + +This module is part of the [Apache Sling](https://sling.apache.org) project. + +The Sling Authentication Service bundle provides the basic mechanisms to authenticate HTTP requests with a JCR repository. The algorithms for extracting authentication details from the requests is extensible by implementing an AuthenticationHandler interface. diff --git a/Java-base/sling-org-apache-sling-auth-core/src/bnd.bnd b/Java-base/sling-org-apache-sling-auth-core/src/bnd.bnd new file mode 100644 index 000000000..c910ed73a --- /dev/null +++ b/Java-base/sling-org-apache-sling-auth-core/src/bnd.bnd @@ -0,0 +1,3 @@ +Import-Package: !javax.jcr,* +DynamicImport-Package: javax.jcr +Bundle-DocURL: http://sling.apache.org/site/authentication.html \ No newline at end of file diff --git a/Java-base/sling-org-apache-sling-auth-core/src/pom.xml b/Java-base/sling-org-apache-sling-auth-core/src/pom.xml new file mode 100644 index 000000000..5dd5b1bd6 --- /dev/null +++ b/Java-base/sling-org-apache-sling-auth-core/src/pom.xml @@ -0,0 +1,150 @@ + + + + + 4.0.0 + + org.apache.sling + sling-bundle-parent + 38 + + + + org.apache.sling.auth.core + 1.4.9-SNAPSHOT + + Apache Sling Auth Core + + The Sling Authentication Service bundle provides the basic + mechanisms to authenticate HTTP requests with a JCR repository. + The algorithms for extracting authentication details from the + requests is extensible by implementing an AuthenticationHandler + interface. + + + + 12315268 + **.impl.** + + + + scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-auth-core.git + scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-auth-core.git + https://gitbox.apache.org/repos/asf?p=sling-org-apache-sling-auth-core.git + HEAD + + + + + org.osgi + org.osgi.annotation.versioning + + + org.osgi + org.osgi.service.component.annotations + + + org.osgi + org.osgi.service.metatype.annotations + + + org.osgi + org.osgi.service.component + + + org.apache.sling + org.apache.sling.api + 2.18.0 + provided + + + org.apache.sling + org.apache.sling.commons.osgi + 2.2.0 + provided + + + javax.jcr + jcr + + + javax.servlet + javax.servlet-api + + + org.osgi + osgi.core + + + org.osgi + org.osgi.service.event + 1.3.1 + provided + + + org.osgi + org.osgi.service.http.whiteboard + 1.1.0 + provided + + + org.slf4j + slf4j-api + + + org.jmock + jmock-junit4 + + + commons-codec + commons-codec + 1.4 + provided + + + + + junit + junit + + + org.mockito + mockito-core + 3.3.3 + test + + + org.slf4j + slf4j-simple + + + junit-addons + junit-addons + 1.4 + test + + + com.google.guava + guava + 15.0 + test + + + diff --git a/Java-base/sling-org-apache-sling-auth-core/src/src/main/java/org/apache/sling/auth/core/AuthConstants.java b/Java-base/sling-org-apache-sling-auth-core/src/src/main/java/org/apache/sling/auth/core/AuthConstants.java new file mode 100644 index 000000000..b0c073c89 --- /dev/null +++ b/Java-base/sling-org-apache-sling-auth-core/src/src/main/java/org/apache/sling/auth/core/AuthConstants.java @@ -0,0 +1,151 @@ +/* + * 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.auth.core; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * The AuthConstants provides a collection of constants used to + * configure and customize the Sling authentication infrastructure. + *

+ * This class can neither be extended from nor can it be instantiated. + * + * @since 1.1 (bundle version 1.0.8) + */ +public final class AuthConstants { + + /** + * The name of the request parameter indicating that the submitted username + * and password should just be checked and a status code be set for success + * (200/OK) or failure (403/FORBIDDEN). + * + * @see AuthUtil#isValidateRequest(HttpServletRequest) + * @see AuthUtil#sendValid(HttpServletResponse) + * @see AuthUtil#sendInvalid(HttpServletRequest, HttpServletResponse) + */ + public static final String PAR_J_VALIDATE = "j_validate"; + + /** + * The name of the request header set by the + * {@link AuthUtil#sendInvalid(HttpServletRequest, HttpServletResponse)} method if the provided + * credentials cannot be used for login. + *

+ * This header may be inspected by clients for a reason why the request + * failed. + * + * @see AuthUtil#sendInvalid(HttpServletRequest, HttpServletResponse) + */ + public static final String X_REASON = "X-Reason"; + + /** + * The name of the request header set by the + * {@link AuthUtil#sendInvalid(HttpServletRequest, HttpServletResponse)} method if the provided + * credentials cannot be used for login. + *

+ * This header may be inspected by clients for a a detailed reason code why the request + * failed. + * + * @see AuthUtil#sendInvalid(HttpServletRequest, HttpServletResponse) + */ + public static final String X_REASON_CODE = "X-Reason-Code"; + + /** + * Service Registration property which may be set by an + * {@link org.apache.sling.auth.core.spi.AuthenticationHandler} service to + * indicate whether its + * {@link org.apache.sling.auth.core.spi.AuthenticationHandler#requestCredentials(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)} + * method supports non-browser requests (according to + * {@link AuthUtil#isBrowserRequest(javax.servlet.http.HttpServletRequest)} + * or not. + *

+ * For backwards compatibility with existing + * {@link org.apache.sling.auth.core.spi.AuthenticationHandler} services the + * default assumption in the absence of this property is that all requests + * are supported. + *

+ * If this property is set to true or yes + * (case-insensitive check) the handler is not called for requests assumed + * to be sent from non-browser clients. Any other value of this property + * indicates support for non-browser requests by the handler. + *

+ * Note that this property only influences whether the + * requestCredentials method is called or not. The + * extractCredentials and dropCredentials are + * called regardless of this property. + */ + public static final String AUTH_HANDLER_BROWSER_ONLY = "sling.auth.browser-only"; + + /** + * Marker property in the + * {@link org.apache.sling.auth.core.spi.AuthenticationInfo} object returned + * by the + * {@link org.apache.sling.auth.core.spi.AuthenticationHandler#extractCredentials(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)} + * method indicating a first authentication considered to be a login. + *

+ * By setting this property to any non-null value an + * {@link org.apache.sling.auth.core.spi.AuthenticationHandler} indicates, + * that the {@link #TOPIC_LOGIN} event should be fired after successfully + * acquiring the ResourceResolver. + */ + public static final String AUTH_INFO_LOGIN = "$$auth.info.login$$"; + + /** + * The topic for the OSGi event which is sent when a user has logged in successfully. + * The event contains at least the {@link org.apache.sling.api.SlingConstants#PROPERTY_USERID} + * and the {@link org.apache.sling.auth.core.spi.AuthenticationInfo#AUTH_TYPE} + * properties. + */ + public static final String TOPIC_LOGIN = "org/apache/sling/auth/core/Authenticator/LOGIN"; + + /** + * The topic for the OSGi event which is sent when a user has failed to login successfully. + * The event contains at least the {@link org.apache.sling.api.SlingConstants#PROPERTY_USERID} + * and the {@link org.apache.sling.auth.core.spi.AuthenticationInfo#AUTH_TYPE} + * properties. + */ + public static final String TOPIC_LOGIN_FAILED = "org/apache/sling/auth/core/Authenticator/LOGIN_FAILED"; + + /** + * Any OSGi service may provide a {@code sling.auth.requirements} registration property which is used + * to dynamically extend the authentication requirements for the {@code AuthenticationSupport}. + * This may for example be set by AuthenticationHandler implementations providing + * a login form to ensure access to the login form does not require authentication. The value + * of this property is a single string, an array of strings or a Collection of strings. + * Each string can be an absolute path (such as /content) or and absolute URI (such as + * http://thehost/content). Optionally each entry may be prefixed by a plus (+) or minus (-) sign + * indicating that authentication is required (plus) or not required (minus). + */ + public static final String AUTH_REQUIREMENTS = "sling.auth.requirements"; + + /** + * The name of the request attribute containing the list of + * request URI suffixes handled by the default authenticator + * org.apache.sling.auth.core.impl.SlingAuthenticator. + * The authenticator will populate this attribute so that login JSPs + * can post j_username and j_password to the correct URI. + * + * @since 1.3.2 (bundle version 1.4.0) + */ + public static final String ATTR_REQUEST_AUTH_URI_SUFFIX = "org.apache.sling.api.include.auth_uri_suffix"; + + private AuthConstants() { + } + +} diff --git a/Java-base/sling-org-apache-sling-auth-core/src/src/main/java/org/apache/sling/auth/core/AuthUtil.java b/Java-base/sling-org-apache-sling-auth-core/src/src/main/java/org/apache/sling/auth/core/AuthUtil.java new file mode 100644 index 000000000..771b8f83f --- /dev/null +++ b/Java-base/sling-org-apache-sling-auth-core/src/src/main/java/org/apache/sling/auth/core/AuthUtil.java @@ -0,0 +1,603 @@ +/* + * 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.auth.core; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLEncoder; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.regex.Pattern; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.sling.api.auth.Authenticator; +import org.apache.sling.api.resource.ResourceResolver; +import org.apache.sling.api.resource.ResourceUtil; +import org.apache.sling.auth.core.spi.AuthenticationHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The AuthUtil provides utility functions for implementations of + * {@link org.apache.sling.auth.core.spi.AuthenticationHandler} services and + * users of the Sling authentication infrastructure. + *

+ * This utility class can neither be extended from nor can it be instantiated. + * + * @since 1.1 (bundle version 1.0.8) + */ +public final class AuthUtil { + + /** + * Request header commonly set by Ajax Frameworks to indicate the request is + * posted as an Ajax request. The value set is expected to be + * {@link #XML_HTTP_REQUEST}. + *

+ * This header is known to be set by JQuery, ExtJS and Prototype. Other + * client-side JavaScript framework most probably also set it. + * + * @see #isAjaxRequest(javax.servlet.http.HttpServletRequest) + */ + private static final String X_REQUESTED_WITH = "X-Requested-With"; + + /** + * The expected value of the {@link #X_REQUESTED_WITH} request header to + * identify a request as an Ajax request. + * + * @see #isAjaxRequest(javax.servlet.http.HttpServletRequest) + */ + private static final String XML_HTTP_REQUEST = "XMLHttpRequest"; + + /** + * Request header providing the clients user agent information used + * by {@link #isBrowserRequest(HttpServletRequest)} to decide whether + * a request is probably sent by a browser or not. + */ + private static final String USER_AGENT = "User-Agent"; + + /** + * String contained in a {@link #USER_AGENT} header indicating a Mozilla + * class browser. Examples of such browsers are Firefox (generally Gecko + * based browsers), Safari, Chrome (probably generally WebKit based + * browsers), and Microsoft IE. + */ + private static final String BROWSER_CLASS_MOZILLA = "Mozilla"; + + /** + * String contained in a {@link #USER_AGENT} header indicating a Opera class + * browser. The only known browser in this class is the Opera browser. + */ + private static final String BROWSER_CLASS_OPERA = "Opera"; + + // no instantiation + private AuthUtil() { + } + + /** + * Returns the value of the named request attribute or parameter as a string + * as follows: + *

    + *
  1. If there is a request attribute of that name, which is a non-empty + * string, it is returned.
  2. + *
  3. If there is a non-empty request parameter of + * that name, this parameter is returned.
  4. + *
  5. Otherwise the defaultValue is returned.
  6. + *
+ * + * @param request The request from which to return the attribute or request + * parameter + * @param name The name of the attribute/parameter + * @param defaultValue The default value to use if neither a non-empty + * string attribute or a non-empty parameter exists in the + * request. + * @return The attribute, parameter or defaultValue as defined + * above. + */ + public static String getAttributeOrParameter( + final HttpServletRequest request, final String name, + final String defaultValue) { + + final String resourceAttr = getAttributeString(request, name); + if (resourceAttr != null) { + return resourceAttr; + } + + final String resource = request.getParameter(name); + if (resource != null && resource.length() > 0) { + return resource; + } + + return defaultValue; + } + + /** + * Returns any resource target to redirect to after successful + * authentication. This method either returns a non-empty string or the + * defaultLoginResource parameter. First the + * resource request attribute is checked. If it is a non-empty + * string, it is returned. Second the resource request + * parameter is checked and returned if it is a non-empty string. + * + * @param request The request providing the attribute or parameter + * @param defaultLoginResource The default login resource value + * @return The non-empty redirection target or + * defaultLoginResource. + */ + public static String getLoginResource(final HttpServletRequest request, + String defaultLoginResource) { + return getAttributeOrParameter(request, Authenticator.LOGIN_RESOURCE, + defaultLoginResource); + } + + /** + * Ensures and returns the {@link Authenticator#LOGIN_RESOURCE} request + * attribute is set to a non-null, non-empty string. If the attribute is not + * currently set, this method sets it as follows: + *
    + *
  1. If the {@link Authenticator#LOGIN_RESOURCE} request parameter is set + * to a non-empty string, that parameter is set
  2. + *
  3. Otherwise if the defaultValue is a non-empty string the + * default value is used
  4. + *
  5. Otherwise the attribute is set to "/"
  6. + *
+ * + * @param request The request to check for the resource attribute + * @param defaultValue The default value to use if the attribute is not set + * and the request parameter is not set. This parameter is + * ignored if it is null or an empty string. + * @return returns the value of resource request attribute + */ + public static String setLoginResourceAttribute( + final HttpServletRequest request, final String defaultValue) { + String resourceAttr = getAttributeString(request, + Authenticator.LOGIN_RESOURCE); + if (resourceAttr == null) { + final String resourcePar = request.getParameter(Authenticator.LOGIN_RESOURCE); + if (resourcePar != null && resourcePar.length() > 0) { + resourceAttr = resourcePar; + } else if (defaultValue != null && defaultValue.length() > 0) { + resourceAttr = defaultValue; + } else { + resourceAttr = "/"; + } + request.setAttribute(Authenticator.LOGIN_RESOURCE, resourceAttr); + } + return resourceAttr; + } + + /** + * Redirects to the given target path appending any parameters provided in + * the parameter map. + *

+ * This method implements the following functionality: + *

+ *

+ * After checking the redirect target and creating the target URL from the + * parameter map, the response buffer is reset and the + * HttpServletResponse.sendRedirect is called. Any headers + * already set before calling this method are preserved. + * + * @param request The request object used to get the current request URI and + * request query string if the params map does not + * have the {@link Authenticator#LOGIN_RESOURCE resource} + * parameter set. + * @param response The response used to send the redirect to the client. + * @param target The redirect target to validate. This path must be prefixed + * with the request's servlet context path. If this parameter is + * not a valid target request as per the + * {@link #isRedirectValid(HttpServletRequest, String)} method + * the target is modified to be the root of the request's + * context. + * @param params The map of parameters to be added to the target path. This + * may be null. + * @throws IOException If an error occurs sending the redirect request + * @throws IllegalStateException If the response was committed or if a + * partial URL is given and cannot be converted into a valid URL + * @throws InternalError If the UTF-8 character encoding is not supported by + * the platform. This should not be caught, because it is a real + * problem if the encoding required by the specification is + * missing. + */ + public static void sendRedirect(final HttpServletRequest request, + final HttpServletResponse response, final String target, + Map params) throws IOException { + + checkAndReset(response); + + StringBuilder b = new StringBuilder(); + if (AuthUtil.isRedirectValid(request, target)) { + b.append(target); + } else if (request.getContextPath().length() == 0) { + b.append("/"); + } else { + b.append(request.getContextPath()); + } + + if (params == null) { + params = new HashMap(); + } + + // ensure the login resource is provided with the redirect + if (params.get(Authenticator.LOGIN_RESOURCE) == null) { + String resource = request.getRequestURI(); + if (request.getQueryString() != null) { + resource += "?" + request.getQueryString(); + } + params.put(Authenticator.LOGIN_RESOURCE, resource); + } + + b.append('?'); + Iterator> ei = params.entrySet().iterator(); + while (ei.hasNext()) { + Entry entry = ei.next(); + if (entry.getKey() != null && entry.getValue() != null) { + try { + b.append(entry.getKey()).append('=').append( + URLEncoder.encode(entry.getValue(), "UTF-8")); + } catch (UnsupportedEncodingException uee) { + throw new InternalError( + "Unexpected UnsupportedEncodingException for UTF-8"); + } + + if (ei.hasNext()) { + b.append('&'); + } + } + } + + response.sendRedirect(b.toString()); + } + + /** + * Returns the name request attribute if it is a non-empty string value. + * + * @param request The request from which to retrieve the attribute + * @param name The name of the attribute to return + * @return The named request attribute or null if the attribute + * is not set or is not a non-empty string value. + */ + private static String getAttributeString(final HttpServletRequest request, + final String name) { + Object resObj = request.getAttribute(name); + if ((resObj instanceof String) && ((String) resObj).length() > 0) { + return (String) resObj; + } + + // not set or not a non-empty string + return null; + } + + /** + * Returns true if the the client just asks for validation of + * submitted username/password credentials. + *

+ * This implementation returns true if the request parameter + * {@link AuthConstants#PAR_J_VALIDATE} is set to true (case-insensitve). If + * the request parameter is not set or to any value other than + * true this method returns false. + * + * @param request The request to provide the parameter to check + * @return true if the {@link AuthConstants#PAR_J_VALIDATE} parameter is set + * to true. + */ + public static boolean isValidateRequest(final HttpServletRequest request) { + return "true".equalsIgnoreCase(request.getParameter(AuthConstants.PAR_J_VALIDATE)); + } + + /** + * Sends a 200/OK response to a credential validation request. + *

+ * This method just overwrites the response status to 200/OK, sends no + * content (content length header set to zero) and prevents caching on + * clients and proxies. Any other response headers set before calling this + * methods are preserved and sent along with the response. + * + * @param response The response object + * @throws IllegalStateException if the response has already been committed + */ + public static void sendValid(final HttpServletResponse response) { + checkAndReset(response); + try { + response.setStatus(HttpServletResponse.SC_OK); + + // explicitly tell we have no content but set content type + // to prevent firefox from trying to parse the response + // (SLING-1841) + response.setContentType("text/plain"); + response.setContentLength(0); + + // prevent the client from aggressively caching the response + // (SLING-1841) + response.setHeader("Pragma", "no-cache"); + response.setHeader("Cache-Control", "no-cache"); + response.addHeader("Cache-Control", "no-store"); + + response.flushBuffer(); + } catch (IOException ioe) { + getLog().error("Failed to send 200/OK response", ioe); + } + } + + /** + * Sends a 403/FORBIDDEN response optionally stating the reason for this + * response code in the {@link AuthConstants#X_REASON} header. The value for the + * {@link AuthConstants#X_REASON} header is taken from + * {@link AuthenticationHandler#FAILURE_REASON} request attribute if set. + *

+ * This method just overwrites the response status to 403/FORBIDDEN, adds + * the {@link AuthConstants#X_REASON} header and sends the reason as result + * back. Any other response headers set before calling this methods are + * preserved and sent along with the response. + * + * @param request The request object + * @param response The response object + * @throws IllegalStateException if the response has already been committed + */ + public static void sendInvalid(final HttpServletRequest request, + final HttpServletResponse response) { + checkAndReset(response); + try { + response.setStatus(HttpServletResponse.SC_FORBIDDEN); + + Object reason = request.getAttribute(AuthenticationHandler.FAILURE_REASON); + Object reasonCode = request.getAttribute(AuthenticationHandler.FAILURE_REASON_CODE); + if (reason != null) { + response.setHeader(AuthConstants.X_REASON, reason.toString()); + if ( reasonCode != null ) { + response.setHeader(AuthConstants.X_REASON_CODE, reasonCode.toString()); + } + response.setContentType("text/plain"); + response.setCharacterEncoding("UTF-8"); + response.getWriter().println(reason); + } + + response.flushBuffer(); + } catch (IOException ioe) { + getLog().error("Failed to send 403/Forbidden response", ioe); + } + } + + /** + * Check if the request is for this authentication handler. + * + * @param request the current request + * @return true if the referer matches this handler, or false otherwise + */ + public static boolean checkReferer(HttpServletRequest request, String loginForm) { + //SLING-2165: if a Referer header is supplied check if it matches the login path for this handler + if ("POST".equals(request.getMethod())) { + String referer = request.getHeader("Referer"); + if (referer != null) { + String expectedPath = String.format("%s%s", request.getContextPath(), loginForm); + try { + URL uri = new URL(referer); + if (!expectedPath.equals(uri.getPath())) { + //not for this selector, so let the next one handle it. + return false; + } + } catch (MalformedURLException e) { + getLog().debug("Failed to parse the referer value for the login form " + loginForm, e); + } + } + } + return true; + } + + /** + * Returns true if the given redirect target is + * valid according to the following list of requirements: + *

+ *

+ * If any of the conditions does not hold, the method returns + * false and logs a warning level message with the + * org.apache.sling.auth.core.AuthUtil logger. + * + * @param request Providing the ResourceResolver attribute and + * the context to resolve the resource from the + * target. This may be null which + * causes the target to not be validated with a + * ResoureResolver + * @param target The redirect target to validate. This path must be + * prefixed with the request's servlet context path. + * @return true if the redirect target can be considered valid + */ + public static boolean isRedirectValid(final HttpServletRequest request, final String target) { + if (target == null || target.length() == 0) { + getLog().warn("isRedirectValid: Redirect target must not be empty or null"); + return false; + } + + try { + new URI(target); + } catch (URISyntaxException e) { + getLog().warn("isRedirectValid: Redirect target '{}' contains illegal characters", target); + return false; + } + + if (target.contains("://")) { + getLog().warn("isRedirectValid: Redirect target '{}' must not be an URL", target); + return false; + } + + if (target.contains("//") || target.contains("/../") || target.contains("/./") || target.endsWith("/.") + || target.endsWith("/..")) { + getLog().warn("isRedirectValid: Redirect target '{}' is not normalized", target); + return false; + } + + final String ctxPath = getContextPath(request); + if (ctxPath.length() > 0 && !target.startsWith(ctxPath)) { + getLog().warn("isRedirectValid: Redirect target '{}' does not start with servlet context path '{}'", + target, ctxPath); + return false; + } + + // special case of requesting the servlet context root path + if (ctxPath.length() == target.length()) { + return true; + } + + final String localTarget = target.substring(ctxPath.length()); + if (!localTarget.startsWith("/")) { + getLog().warn( + "isRedirectValid: Redirect target '{}' without servlet context path '{}' must be an absolute path", + target, ctxPath); + return false; + } + + final int query = localTarget.indexOf('?'); + final String path = (query > 0) ? localTarget.substring(0, query) : localTarget; + + ResourceResolver resolver = getResourceResolver(request); + if (resolver != null) { + // assume all is fine if the path resolves to a resource + if (!ResourceUtil.isNonExistingResource(resolver.resolve(request, path))) { + return true; + } + + // not resolving to a resource, check for illegal characters + } + + final Pattern illegal = Pattern.compile("[<>'\"]"); + if (illegal.matcher(path).find()) { + getLog().warn("isRedirectValid: Redirect target '{}' must not contain any of <>'\"", target); + return false; + } + + return true; + } + + /** + * Returns the context path from the request or an empty string if the + * request is null. + */ + private static String getContextPath(final HttpServletRequest request) { + if (request != null) { + return request.getContextPath(); + } + return ""; + } + + /** + * Returns the resource resolver set as the + * {@link AuthenticationSupport#REQUEST_ATTRIBUTE_RESOLVER} request + * attribute or null if the request object is null + * or the resource resolver is not present. + */ + private static ResourceResolver getResourceResolver(final HttpServletRequest request) { + if (request != null) { + return (ResourceResolver) request.getAttribute(AuthenticationSupport.REQUEST_ATTRIBUTE_RESOLVER); + } + return null; + } + + /** + * Returns true if the given request can be assumed to be sent + * by a client browser such as Firefix, Internet Explorer, etc. + *

+ * This method inspects the User-Agent header and returns + * true if the header contains the string Mozilla (known + * to be contained in Firefox, Internet Explorer, WebKit-based browsers + * User-Agent) or Opera (known to be contained in the Opera + * User-Agent). + * + * @param request The request to inspect + * @return true if the request is assumed to be sent by a + * browser. + */ + public static boolean isBrowserRequest(final HttpServletRequest request) { + final String userAgent = request.getHeader(USER_AGENT); + if (userAgent != null && (userAgent.contains(BROWSER_CLASS_MOZILLA) || userAgent.contains(BROWSER_CLASS_OPERA))) { + return true; + } + return false; + } + + /** + * Returns true if the request is to be considered an AJAX + * request placed using the XMLHttpRequest browser host object. + * Currently a request is considered an AJAX request if the client sends the + * X-Requested-With request header set to XMLHttpRequest + * . + * + * @param request The current request + * @return true if the request can be considered an AJAX + * request. + */ + public static boolean isAjaxRequest(final HttpServletRequest request) { + return XML_HTTP_REQUEST.equals(request.getHeader(X_REQUESTED_WITH)); + } + + /** + * Checks whether the response has already been committed. If so an + * IllegalStateException is thrown. Otherwise the response + * buffer is cleared leaving any headers and status already set untouched. + * + * @param response The response to check and reset. + * @throws IllegalStateException if the response has already been committed + */ + private static void checkAndReset(final HttpServletResponse response) { + if (response.isCommitted()) { + throw new IllegalStateException("Response is already committed"); + } + response.resetBuffer(); + } + + /** + * Helper method returning a org.apache.sling.auth.core.AuthUtil logger. + */ + private static Logger getLog() { + return LoggerFactory.getLogger("org.apache.sling.auth.core.AuthUtil"); + } +} diff --git a/Java-base/sling-org-apache-sling-auth-core/src/src/main/java/org/apache/sling/auth/core/AuthenticationSupport.java b/Java-base/sling-org-apache-sling-auth-core/src/src/main/java/org/apache/sling/auth/core/AuthenticationSupport.java new file mode 100644 index 000000000..7257110fd --- /dev/null +++ b/Java-base/sling-org-apache-sling-auth-core/src/src/main/java/org/apache/sling/auth/core/AuthenticationSupport.java @@ -0,0 +1,122 @@ +/* + * 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.auth.core; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.osgi.annotation.versioning.ProviderType; + +/** + * The AuthenticationSupport provides the service API used to + * implement the HttpContext.handleSecurity method as defined in + * the OSGi Http Service specification. + *

+ * Bundles registering servlets and/or resources with custom + * HttpContext implementations may implement the + * handleSecurity method using this service. The + * {@link #handleSecurity(HttpServletRequest, HttpServletResponse)} method + * implemented by this service exactly implements the specification of the + * HttpContext.handleSecurity method. + *

+ * A simple implementation of the HttpContext interface based on + * this could be (using SCR JavaDoc tags of the Maven SCR Plugin) : + * + *

+ * /** @scr.component */
+ * public class MyHttpContext implements HttpContext {
+ *     /** @scr.reference */
+ *     private AuthenticationSupport authSupport;
+ *
+ *     /** @scr.reference */
+ *     private MimeTypeService mimeTypes;
+ *
+ *     public boolean handleSecurity(HttpServletRequest request,
+ *             HttpServletResponse response) {
+ *         return authSupport.handleSecurity(request, response);
+ *     }
+ *
+ *     public URL getResource(String name) {
+ *         return null;
+ *     }
+ *
+ *     public String getMimeType(String name) {
+ *         return mimeTypes.getMimeType(name);
+ *     }
+ * }
+ * 
+ *

+ * This interface is implemented by this bundle and is not intended to be + * implemented by client bundles. + */ +@ProviderType +public interface AuthenticationSupport { + + /** + * The name under which this service is registered. + */ + static final String SERVICE_NAME = "org.apache.sling.auth.core.AuthenticationSupport"; + + /** + * The name of the request attribute set by the + * {@link #handleSecurity(HttpServletRequest, HttpServletResponse)} method + * if authentication succeeds and true is returned. + *

+ * The request attribute is set to a Sling ResourceResolver + * attached to the JCR repository using the credentials provided by the + * request. + */ + static final String REQUEST_ATTRIBUTE_RESOLVER = "org.apache.sling.auth.core.ResourceResolver"; + + /** + * The name of the request parameter indicating where to redirect to after + * successful authentication (and optional impersonation). This parameter is + * respected if either anonymous authentication or regular authentication + * succeed. + *

+ * If authentication fails, either because the credentials are wrong or + * because anonymous authentication fails or because anonymous + * authentication is not allowed for the request, the parameter is ignored + * and the + * {@link org.apache.sling.auth.core.spi.AuthenticationHandler#requestCredentials(HttpServletRequest, HttpServletResponse)} + * method is called to request authentication. + */ + static final String REDIRECT_PARAMETER = "sling.auth.redirect"; + + /** + * Handles security on behalf of a custom OSGi Http Service + * HttpContext instance extracting credentials from the request + * using any registered + * {@link org.apache.sling.auth.core.spi.AuthenticationHandler} services. + * If the credentials can be extracted and used to log into the JCR + * repository this method sets the request attributes required by the OSGi + * Http Service specification plus the {@link #REQUEST_ATTRIBUTE_RESOLVER} + * attribute. + * + * @param request The HTTP request to be authenticated + * @param response The HTTP response to send any response to in case of + * problems. + * @return true if authentication succeeded and the request + * attributes are set. If false is returned the request + * is immediately terminated and no request attributes are set. + */ + boolean handleSecurity(HttpServletRequest request, + HttpServletResponse response); + +} diff --git a/Java-base/sling-org-apache-sling-auth-core/src/src/main/java/org/apache/sling/auth/core/impl/AbstractAuthenticationHandlerHolder.java b/Java-base/sling-org-apache-sling-auth-core/src/src/main/java/org/apache/sling/auth/core/impl/AbstractAuthenticationHandlerHolder.java new file mode 100644 index 000000000..91f63ccdf --- /dev/null +++ b/Java-base/sling-org-apache-sling-auth-core/src/src/main/java/org/apache/sling/auth/core/impl/AbstractAuthenticationHandlerHolder.java @@ -0,0 +1,198 @@ +/* + * 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.auth.core.impl; + +import java.io.IOException; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.sling.auth.core.spi.AuthenticationFeedbackHandler; +import org.apache.sling.auth.core.spi.AuthenticationHandler; +import org.apache.sling.auth.core.spi.AuthenticationInfo; +import org.osgi.framework.ServiceReference; + +/** + * The AbstractAuthenticationHandlerHolder is a base class to + * represent authentication handlers (both legacy and new ones) for use in the + * {@link SlingAuthenticator}. + */ +public abstract class AbstractAuthenticationHandlerHolder extends + PathBasedHolder implements AuthenticationHandler { + + protected AbstractAuthenticationHandlerHolder(final String fullPath, + final ServiceReference serviceReference) { + super(fullPath, serviceReference); + } + + /** + * Sets the {@link AuthenticationHandler#PATH_PROPERTY} request attribute to + * this {@link PathBasedHolder#fullPath} and calls the + * {@link #extractCredentials(HttpServletRequest, HttpServletResponse)} to + * have the credentials extracted from the request. + * + * @param request the current request + * @param response the current response + * @return the result of calling + * {@link #doExtractCredentials(HttpServletRequest, HttpServletResponse)} + */ + public final AuthenticationInfo extractCredentials( + HttpServletRequest request, HttpServletResponse response) { + + final Object oldPathAttr = setPath(request); + try { + return doExtractCredentials(request, response); + } finally { + resetPath(request, oldPathAttr); + } + + } + + /** + * Sets the {@link AuthenticationHandler#PATH_PROPERTY} request attribute to + * this {@link PathBasedHolder#fullPath} and calls the + * {@link #doRequestCredentials(HttpServletRequest, HttpServletResponse)} to + * have the credentials requested from the client. + * + * @param request the current request + * @param response the current response + * @return the result of calling + * {@link #doRequestCredentials(HttpServletRequest, HttpServletResponse)} + * @throws IOException if an error occurs interacting with the client + */ + public final boolean requestCredentials(HttpServletRequest request, + HttpServletResponse response) throws IOException { + final Object oldPathAttr = setPath(request); + try { + return doRequestCredentials(request, response); + } finally { + resetPath(request, oldPathAttr); + } + } + + /** + * Sets the {@link AuthenticationHandler#PATH_PROPERTY} request attribute to + * this {@link PathBasedHolder#fullPath} and calls the + * {@link #doDropCredentials(HttpServletRequest, HttpServletResponse)} to + * have the credentials dropped by the held authentication handler. + * + * @param request the current request + * @param response the current response + * @throws IOException if an error occurs interacting with the client + */ + public final void dropCredentials(HttpServletRequest request, + HttpServletResponse response) throws IOException { + final Object oldPathAttr = setPath(request); + try { + doDropCredentials(request, response); + } finally { + resetPath(request, oldPathAttr); + } + } + + // --------- API to be implemented + + /** + * Returns a feedback handler provided by the authentication handler held by + * this instance or null if none is provided. + */ + protected abstract AuthenticationFeedbackHandler getFeedbackHandler(); + + /** + * Calls the actual authentication handler to extract the credentials from + * the request. + * + * @param request The current request + * @param response The current response + * @return as returned from the called authentication handler + * @see #extractCredentials(HttpServletRequest, HttpServletResponse) + */ + protected abstract AuthenticationInfo doExtractCredentials( + HttpServletRequest request, HttpServletResponse response); + + /** + * Calls the actual authentication handler to request the credentials from + * the client. + * + * @param request The current request + * @param response The current response + * @return as returned from the called authentication handler + * @throws IOException if an error occurs sending back any response to the + * client. + * @see #requestCredentials(HttpServletRequest, HttpServletResponse) + */ + protected abstract boolean doRequestCredentials(HttpServletRequest request, + HttpServletResponse response) throws IOException; + + /** + * Calls the actual authentication handler to request the credentials from + * the client. + * + * @param request The current request + * @param response The current response + * @throws IOException if an error occurs sending back any response to the + * client. + * @see #dropCredentials(HttpServletRequest, HttpServletResponse) + */ + protected abstract void doDropCredentials(HttpServletRequest request, + HttpServletResponse response) throws IOException; + + // ---------- internal + + /** + * Sets the {@link PathBasedHolder#fullPath} as the + * {@link AuthenticationHandler#PATH_PROPERTY} request attribute. + */ + private Object setPath(final HttpServletRequest request) { + return setRequestAttribute(request, + AuthenticationHandler.PATH_PROPERTY, fullPath); + } + + /** + * Sets the given odlValue as the + * {@link AuthenticationHandler#PATH_PROPERTY} request attribute. + */ + private void resetPath(final HttpServletRequest request, Object oldValue) { + setRequestAttribute(request, AuthenticationHandler.PATH_PROPERTY, + oldValue); + } + + /** + * Sets the named request attribute to the new value and returns the + * previous value. + * + * @param request The request object whose attribute is to be set. + * @param name The name of the attribute to be set. + * @param value The new value of the attribute. If this is null + * the attribute is actually removed from the request. + * @return The previous value of the named request attribute or + * null if it was not set. + */ + private static Object setRequestAttribute(HttpServletRequest request, + String name, Object value) { + Object oldValue = request.getAttribute(name); + if (value == null) { + request.removeAttribute(name); + } else { + request.setAttribute(name, value); + } + return oldValue; + } + +} \ No newline at end of file diff --git a/Java-base/sling-org-apache-sling-auth-core/src/src/main/java/org/apache/sling/auth/core/impl/AuthenticationHandlerHolder.java b/Java-base/sling-org-apache-sling-auth-core/src/src/main/java/org/apache/sling/auth/core/impl/AuthenticationHandlerHolder.java new file mode 100644 index 000000000..066362b2f --- /dev/null +++ b/Java-base/sling-org-apache-sling-auth-core/src/src/main/java/org/apache/sling/auth/core/impl/AuthenticationHandlerHolder.java @@ -0,0 +1,154 @@ +/* + * 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.auth.core.impl; + +import java.io.IOException; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.sling.auth.core.AuthConstants; +import org.apache.sling.auth.core.AuthUtil; +import org.apache.sling.auth.core.spi.AuthenticationFeedbackHandler; +import org.apache.sling.auth.core.spi.AuthenticationHandler; +import org.apache.sling.auth.core.spi.AuthenticationInfo; +import org.apache.sling.commons.osgi.PropertiesUtil; +import org.osgi.framework.ServiceReference; + +/** + * The AuthenticationHandlerHolder class represents an + * authentication handler service in the internal data structure of the + * {@link SlingAuthenticator}. + */ +final class AuthenticationHandlerHolder extends + AbstractAuthenticationHandlerHolder { + + // the actual authentication handler + private final AuthenticationHandler handler; + + // the supported authentication type of the handler + private final String authType; + + // whether requestCredentials only for browsers + private final boolean browserOnlyRequestCredentials; + + AuthenticationHandlerHolder(final String fullPath, + final AuthenticationHandler handler, + final ServiceReference serviceReference) { + super(fullPath, serviceReference); + + final String browserOnly = PropertiesUtil.toString(serviceReference.getProperty(AuthConstants.AUTH_HANDLER_BROWSER_ONLY), null); + + // assign the fields + this.handler = handler; + this.authType = PropertiesUtil.toString(serviceReference.getProperty(TYPE_PROPERTY), null); + this.browserOnlyRequestCredentials = "true".equalsIgnoreCase(browserOnly) + || "yes".equalsIgnoreCase(browserOnly); + } + + @Override + protected AuthenticationFeedbackHandler getFeedbackHandler() { + if (handler instanceof AuthenticationFeedbackHandler) { + return (AuthenticationFeedbackHandler) handler; + } + return null; + } + + @Override + public AuthenticationInfo doExtractCredentials(HttpServletRequest request, + HttpServletResponse response) { + return handler.extractCredentials(request, response); + } + + @Override + public boolean doRequestCredentials(HttpServletRequest request, + HttpServletResponse response) throws IOException { + + // call handler if ok by its authentication type + if (doesRequestCredentials(request)) { + return handler.requestCredentials(request, response); + } + + // no credentials have been requested + return false; + } + + @Override + public void doDropCredentials(HttpServletRequest request, + HttpServletResponse response) throws IOException { + handler.dropCredentials(request, response); + } + + @Override + public boolean equals(Object obj) { + + // equality is the base class equality (based on the fullpath) + // and the encapsulated holders being the same. + if (super.equals(obj)) { + if (obj.getClass() == getClass()) { + AuthenticationHandlerHolder other = (AuthenticationHandlerHolder) obj; + return other.handler == handler; + } + } + + // handlers are not the same, so the holders are not the same + return false; + } + + @Override + public String toString() { + return handler.toString(); + } + + /** + * Returns true if the requestCredentials method + * of the held authentication handler should be called or not: + *