content: /*
   * 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.ambari.server.api;
  
  import java.io.IOException;
  import java.net.URLDecoder;
  import java.util.regex.Matcher;
  import java.util.regex.Pattern;
  
  import jakarta.servlet.Filter;
  import jakarta.servlet.FilterChain;
  import jakarta.servlet.FilterConfig;
  import jakarta.servlet.ServletException;
  import jakarta.servlet.ServletRequest;
  import jakarta.servlet.ServletResponse;
  import jakarta.servlet.http.HttpServletRequest;
  import jakarta.servlet.http.HttpServletRequestWrapper;
  
  import org.apache.ambari.server.security.authorization.AuthorizationHelper;
  
  /**
   * This filter overrides usernames found in request url.
   */
  public class UserNameOverrideFilter implements Filter {
  
    // Regex for extracting user name component from the user related api request Uris
    private final static Pattern USER_NAME_IN_URI_REGEXP = Pattern.compile("(?<pre>.*/users/)(?<username>[^/]+)(?<post>(/.*)?)");
  
    /**
     * Called by the web container to indicate to a filter that it is
     * being placed into service.
     *
     * <p>The servlet container calls the init
     * method exactly once after instantiating the filter. The init
     * method must complete successfully before the filter is asked to do any
     * filtering work.
     *
     * <p>The web container cannot place the filter into service if the init
     * method either
     * <ol>
     * <li>Throws a ServletException
     * <li>Does not return within a time period defined by the web container
     * </ol>
     *
     * @param filterConfig
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
  
    }
  
    /**
     * The <code>doFilter</code> method of the Filter is called by the
     * container each time a request/response pair is passed through the
     * chain due to a client request for a resource at the end of the chain.
     * The FilterChain passed in to this method allows the Filter to pass
     * on the request and response to the next entity in the chain.
     *
     * Verify if this a user related request by checking that the Uri of the request contains
     * username and resolves the username to actual ambari user name if username
     * is a login alias.
     *
     * @param request
     * @param response
     * @param chain
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
      if (request instanceof HttpServletRequest) {
        final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        Matcher userNameMatcher = getUserNameMatcher(httpServletRequest.getRequestURI());
  
        if (userNameMatcher.find()) {
          String userNameFromUri = URLDecoder.decode(userNameMatcher.group("username"), "UTF-8");
          final String userName = AuthorizationHelper.resolveLoginAliasToUserName(userNameFromUri);
  
          if (!userNameFromUri.equals(userName)) {
            final String requestUriOverride = String.format("%s%s%s", userNameMatcher.group("pre"), userName, userNameMatcher.group("post"));
  
            request = new HttpServletRequestWrapper(httpServletRequest) {
              @Override
              public String getRequestURI() {
                return requestUriOverride;
              }
            };
  
          }
        }
      }
  
      chain.doFilter(request, response);
    }
  
    /**
     * Returns a {@link Matcher} created from {@link #USER_NAME_IN_URI_REGEXP} for the
     * provided requestUri.
     * @param requestUri the Uri the Matcher is created for.
     * @return the matcher
     */
    protected Matcher getUserNameMatcher(String requestUri) {
      return USER_NAME_IN_URI_REGEXP.matcher(requestUri);
    }
  
    /**
     * Called by the web container to indicate to a filter that it is being
     * taken out of service.
     *
     * <p>This method is only called once all threads within the filter's
     * doFilter method have exited or after a timeout period has passed.
     * After the web container calls this method, it will not call the
     * doFilter method again on this instance of the filter.
     *
     * <p>This method gives the filter an opportunity to clean up any
     * resources that are being held (for example, memory, file handles,
     * threads) and make sure that any persistent state is synchronized
     * with the filter's current state in memory.
     */
    @Override
    public void destroy() {
  
    }
  }
  