001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.rest.server.auth;
018
019import static org.apache.juneau.commons.utils.Shorts.*;
020
021import java.util.*;
022
023import org.apache.juneau.rest.server.*;
024
025import jakarta.servlet.http.*;
026
027/**
028 * Resource-level authentication SPI for {@link Rest @Rest} resources.
029 *
030 * <p>
031 * Resolves a request's {@link java.security.Principal} and roles, reusing the same {@link Authenticator}
032 * implementations (SAML/OAuth/JWT/API-key) used by the servlet-filter layer.  Same three-state contract as
033 * {@link Authenticator}:
034 * <ul>
035 *    <li>{@link Optional#empty()} &mdash; does not apply (anonymous passthrough).
036 *    <li>{@link Optional#of(Object) Optional.of(AuthResult)} &mdash; authentication succeeded.
037 *    <li>throw {@link AuthenticationException} &mdash; credentials present but invalid.
038 * </ul>
039 *
040 * <h5 class='section'>See Also:</h5><ul>
041 *    <li class='jc'>{@link Authenticator}
042 *    <li class='jc'>{@link AuthResult}
043 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/RestServerAuthenticator">REST Authenticator — Resource-Level Authentication</a>
044 * </ul>
045 *
046 * @since 10.0.0
047 */
048public abstract class RestAuthenticator {
049
050   /**
051    * Resolves identity + roles for the request.
052    *
053    * @param req The REST request. Never <jk>null</jk>.
054    * @return The auth result, or {@link Optional#empty()} if this authenticator does not apply.
055    * @throws AuthenticationException If credentials are present but invalid.
056    */
057   public abstract Optional<AuthResult> authenticate(RestRequest req) throws AuthenticationException;
058
059   /**
060    * Framework entry point.
061    *
062    * <p>
063    * The default implementation delegates to {@link #authenticate(RestRequest)}.  The framework always passes a
064    * {@link RestRequest}; the separate signature lets adapters operate on a raw {@link HttpServletRequest}.
065    *
066    * @param req The HTTP request (always a {@link RestRequest} in framework wiring).
067    * @return The auth result, or {@link Optional#empty()} if this authenticator does not apply.
068    * @throws AuthenticationException If credentials are present but invalid.
069    */
070   Optional<AuthResult> authenticateRaw(HttpServletRequest req) throws AuthenticationException {
071      return authenticate((RestRequest) req);
072   }
073
074   /**
075    * Adapts any {@link Authenticator} (e.g. an {@link AuthFilter} or {@link AuthFilterChain} bean) into a
076    * {@link RestAuthenticator}.
077    *
078    * @param a The authenticator to adapt. Must not be <jk>null</jk>.
079    * @return A new {@link RestAuthenticator}.
080    */
081   public static RestAuthenticator of(Authenticator a) {
082      return new RestAuthenticator() {
083         @Override public Optional<AuthResult> authenticate(RestRequest req) throws AuthenticationException {
084            return a.authenticate(req);
085         }
086         @Override Optional<AuthResult> authenticateRaw(HttpServletRequest req) throws AuthenticationException {
087            return a.authenticate(req);
088         }
089      };
090   }
091
092   /**
093    * Sentinel "unset" type for {@link Rest#authenticator() @Rest(authenticator=...)};
094    * never authenticates.
095    */
096   public static final class Null extends RestAuthenticator {
097      @Override public Optional<AuthResult> authenticate(RestRequest req) {
098         return oe();
099      }
100      @Override Optional<AuthResult> authenticateRaw(HttpServletRequest req) {
101         return oe();
102      }
103   }
104}