| /* |
| * 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.unomi.rest.authentication; |
| |
| import org.apache.cxf.interceptor.security.JAASLoginInterceptor; |
| import org.apache.cxf.interceptor.security.RolePrefixSecurityContextImpl; |
| import org.apache.cxf.jaxrs.security.JAASAuthenticationFilter; |
| import org.apache.cxf.jaxrs.utils.JAXRSUtils; |
| import org.apache.cxf.security.SecurityContext; |
| import org.apache.karaf.jaas.boot.principal.RolePrincipal; |
| import org.apache.karaf.jaas.boot.principal.UserPrincipal; |
| |
| import javax.annotation.Priority; |
| import javax.security.auth.Subject; |
| import javax.ws.rs.Priorities; |
| import javax.ws.rs.container.ContainerRequestContext; |
| import javax.ws.rs.container.ContainerRequestFilter; |
| import javax.ws.rs.container.PreMatching; |
| import java.io.IOException; |
| import java.util.*; |
| |
| /** |
| * A wrapper filter around JAASAuthenticationFilter so that we can deactivate JAAS login around some resources and make |
| * them publicly accessible. |
| */ |
| @PreMatching |
| @Priority(Priorities.AUTHENTICATION) |
| public class AuthenticationFilter implements ContainerRequestFilter { |
| |
| // Guest user config |
| public static final String GUEST_USERNAME = "guest"; |
| public static final String GUEST_DEFAULT_ROLE = "ROLE_UNOMI_PUBLIC"; |
| private static final List<String> GUEST_ROLES = Collections.singletonList(GUEST_DEFAULT_ROLE); |
| private static final Subject GUEST_SUBJECT = new Subject(); |
| static { |
| GUEST_SUBJECT.getPrincipals().add(new UserPrincipal(GUEST_USERNAME)); |
| for (String roleName : GUEST_ROLES) { |
| GUEST_SUBJECT.getPrincipals().add(new RolePrincipal(roleName)); |
| } |
| } |
| |
| // JAAS config |
| private static final String ROLE_CLASSIFIER = "ROLE_UNOMI"; |
| private static final String ROLE_CLASSIFIER_TYPE = JAASLoginInterceptor.ROLE_CLASSIFIER_PREFIX; |
| private static final String REALM_NAME = "cxs"; |
| private static final String CONTEXT_NAME = "karaf"; |
| |
| private final JAASAuthenticationFilter jaasAuthenticationFilter; |
| private final RestAuthenticationConfig restAuthenticationConfig; |
| |
| public AuthenticationFilter(RestAuthenticationConfig restAuthenticationConfig) { |
| this.restAuthenticationConfig = restAuthenticationConfig; |
| |
| // Build wrapped jaas filter |
| jaasAuthenticationFilter = new JAASAuthenticationFilter(); |
| jaasAuthenticationFilter.setRoleClassifier(ROLE_CLASSIFIER); |
| jaasAuthenticationFilter.setRoleClassifierType(ROLE_CLASSIFIER_TYPE); |
| jaasAuthenticationFilter.setContextName(CONTEXT_NAME); |
| jaasAuthenticationFilter.setRealmName(REALM_NAME); |
| } |
| |
| @Override |
| public void filter(ContainerRequestContext requestContext) throws IOException { |
| if (isPublicPath(requestContext)) { |
| JAXRSUtils.getCurrentMessage().put(SecurityContext.class, |
| new RolePrefixSecurityContextImpl(GUEST_SUBJECT, ROLE_CLASSIFIER, ROLE_CLASSIFIER_TYPE)); |
| } else{ |
| jaasAuthenticationFilter.filter(requestContext); |
| } |
| } |
| |
| private boolean isPublicPath(ContainerRequestContext requestContext) { |
| // First we do some quick checks to protect against malformed requests |
| // TODO should be handle by input validation ? |
| if (requestContext.getMethod() == null || |
| requestContext.getMethod().length() > 10 || |
| requestContext.getUriInfo().getPath() == null) { |
| return false; |
| } |
| |
| // check if current path is matching any public path patterns |
| String currentPath = requestContext.getMethod() + " " + requestContext.getUriInfo().getPath(); |
| return restAuthenticationConfig.getPublicPathPatterns().stream().anyMatch(pattern -> pattern.matcher(currentPath).matches()); |
| } |
| } |