All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.camunda.bpm.engine.rest.security.auth.ProcessEngineAuthenticationFilter Maven / Gradle / Ivy

There is a newer version: 7.18.0-alpha5
Show newest version
/*
 * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
 * under one or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership. Camunda licenses this file to you under the Apache License,
 * Version 2.0; 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.camunda.bpm.engine.rest.security.auth;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response.Status;

import org.camunda.bpm.engine.ProcessEngine;
import org.camunda.bpm.engine.identity.Group;
import org.camunda.bpm.engine.identity.Tenant;
import org.camunda.bpm.engine.rest.dto.ExceptionDto;
import org.camunda.bpm.engine.rest.exception.InvalidRequestException;
import org.camunda.bpm.engine.rest.impl.NamedProcessEngineRestServiceImpl;
import org.camunda.bpm.engine.rest.util.EngineUtil;

import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * 

* Servlet filter to plug in authentication. *

* *

Valid init-params:

* * * * * * * * * * * *
ParameterRequiredExpected value
{@value #AUTHENTICATION_PROVIDER_PARAM}yesAn implementation of {@link AuthenticationProvider}
{@value #SERVLET_PATH_PREFIX}noThe expected servlet path. Should only be set, if the underlying JAX-RS application is not deployed as a servlet (e.g. Resteasy allows deployments * as a servlet filter). Value has to match what would be the {@link HttpServletRequest#getServletPath()} if it was deployed as a servlet.
* * @author Thorben Lindhauer */ public class ProcessEngineAuthenticationFilter implements Filter { // regexes for urls that may be accessed unauthorized protected static final Pattern[] WHITE_LISTED_URL_PATTERNS = new Pattern[] { Pattern.compile("^" + NamedProcessEngineRestServiceImpl.PATH + "/?") }; protected static final Pattern ENGINE_REQUEST_URL_PATTERN = Pattern.compile("^" + NamedProcessEngineRestServiceImpl.PATH + "/(.*?)(/|$)"); protected static final String DEFAULT_ENGINE_NAME = "default"; // init params public static final String AUTHENTICATION_PROVIDER_PARAM = "authentication-provider"; public static final String SERVLET_PATH_PREFIX = "rest-url-pattern-prefix"; protected AuthenticationProvider authenticationProvider; protected String servletPathPrefix; @Override public void init(FilterConfig filterConfig) throws ServletException { String authenticationProviderClassName = filterConfig.getInitParameter(AUTHENTICATION_PROVIDER_PARAM); if (authenticationProviderClassName == null) { throw new ServletException("Cannot instantiate authentication filter: no authentication provider set. init-param " + AUTHENTICATION_PROVIDER_PARAM + " missing"); } try { Class authenticationProviderClass = Class.forName(authenticationProviderClassName); authenticationProvider = (AuthenticationProvider) authenticationProviderClass.newInstance(); } catch (ClassNotFoundException e) { throw new ServletException("Cannot instantiate authentication filter: authentication provider not found", e); } catch (InstantiationException e) { throw new ServletException("Cannot instantiate authentication filter: cannot instantiate authentication provider", e); } catch (IllegalAccessException e) { throw new ServletException("Cannot instantiate authentication filter: constructor not accessible", e); } catch (ClassCastException e) { throw new ServletException("Cannot instantiate authentication filter: authentication provider does not implement interface " + AuthenticationProvider.class.getName(), e); } servletPathPrefix = filterConfig.getInitParameter(SERVLET_PATH_PREFIX); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse resp = (HttpServletResponse) response; String servletPath = servletPathPrefix; if (servletPath == null) { servletPath = req.getServletPath(); } String requestUrl = req.getRequestURI().substring(req.getContextPath().length() + servletPath.length()); boolean requiresEngineAuthentication = requiresEngineAuthentication(requestUrl); if (!requiresEngineAuthentication) { chain.doFilter(request, response); return; } String engineName = extractEngineName(requestUrl); ProcessEngine engine = getAddressedEngine(engineName); if (engine == null) { resp.setStatus(Status.NOT_FOUND.getStatusCode()); ExceptionDto exceptionDto = new ExceptionDto(); exceptionDto.setType(InvalidRequestException.class.getSimpleName()); exceptionDto.setMessage("Process engine " + engineName + " not available"); ObjectMapper objectMapper = new ObjectMapper(); resp.setContentType(MediaType.APPLICATION_JSON); objectMapper.writer().writeValue(resp.getWriter(), exceptionDto); resp.getWriter().flush(); return; } AuthenticationResult authenticationResult = authenticationProvider.extractAuthenticatedUser(req, engine); if (authenticationResult.isAuthenticated()) { try { String authenticatedUser = authenticationResult.getAuthenticatedUser(); List groups = authenticationResult.getGroups(); List tenants = authenticationResult.getTenants(); setAuthenticatedUser(engine, authenticatedUser, groups, tenants); chain.doFilter(request, response); } finally { clearAuthentication(engine); } } else { resp.setStatus(Status.UNAUTHORIZED.getStatusCode()); authenticationProvider.augmentResponseByAuthenticationChallenge(resp, engine); } } @Override public void destroy() { } protected void setAuthenticatedUser(ProcessEngine engine, String userId, List groupIds, List tenantIds) { if (groupIds == null) { groupIds = getGroupsOfUser(engine, userId); } if (tenantIds == null) { tenantIds = getTenantsOfUser(engine, userId); } engine.getIdentityService().setAuthentication(userId, groupIds, tenantIds); } protected List getGroupsOfUser(ProcessEngine engine, String userId) { List groups = engine.getIdentityService().createGroupQuery() .groupMember(userId) .list(); List groupIds = new ArrayList(); for (Group group : groups) { groupIds.add(group.getId()); } return groupIds; } protected List getTenantsOfUser(ProcessEngine engine, String userId) { List tenants = engine.getIdentityService().createTenantQuery() .userMember(userId) .includingGroupsOfUser(true) .list(); List tenantIds = new ArrayList(); for(Tenant tenant : tenants) { tenantIds.add(tenant.getId()); } return tenantIds; } protected void clearAuthentication(ProcessEngine engine) { engine.getIdentityService().clearAuthentication(); } protected boolean requiresEngineAuthentication(String requestUrl) { for (Pattern whiteListedUrlPattern : WHITE_LISTED_URL_PATTERNS) { Matcher matcher = whiteListedUrlPattern.matcher(requestUrl); if (matcher.matches()) { return false; } } return true; } /** * May not return null */ protected String extractEngineName(String requestUrl) { Matcher matcher = ENGINE_REQUEST_URL_PATTERN.matcher(requestUrl); if (matcher.find()) { return matcher.group(1); } else { // any request that does not match a specific engine and is not an /engine request // is mapped to the default engine return DEFAULT_ENGINE_NAME; } } protected ProcessEngine getAddressedEngine(String engineName) { return EngineUtil.lookupProcessEngine(engineName); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy