/** * 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.cxf.jaxrs.security; import java.net.URI; import java.util.Arrays; import java.util.List; import javax.annotation.Priority; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.login.Configuration; import javax.ws.rs.Priorities; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestFilter; import javax.ws.rs.container.PreMatching; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.ResponseBuilder; import javax.ws.rs.core.UriBuilder; import org.apache.cxf.common.util.StringUtils; import org.apache.cxf.interceptor.security.AuthenticationException; import org.apache.cxf.interceptor.security.JAASLoginInterceptor; import org.apache.cxf.interceptor.security.NamePasswordCallbackHandler; import org.apache.cxf.jaxrs.impl.HttpHeadersImpl; import org.apache.cxf.jaxrs.utils.HttpUtils; import org.apache.cxf.jaxrs.utils.JAXRSUtils; import org.apache.cxf.message.Message; @PreMatching @Priority(Priorities.AUTHENTICATION) public class JAASAuthenticationFilter implements ContainerRequestFilter { private static final List<MediaType> HTML_MEDIA_TYPES = Arrays.asList(MediaType.APPLICATION_XHTML_XML_TYPE, MediaType.TEXT_HTML_TYPE); private URI redirectURI; private String realmName; private boolean ignoreBasePath = true; private JAASLoginInterceptor interceptor; public JAASAuthenticationFilter() { interceptor = new JAASLoginInterceptor() { protected CallbackHandler getCallbackHandler(String name, String password) { return JAASAuthenticationFilter.this.getCallbackHandler(name, password); } }; interceptor.setUseDoAs(false); } @Deprecated public void setRolePrefix(String name) { interceptor.setRolePrefix(name); } public void setIgnoreBasePath(boolean ignore) { this.ignoreBasePath = ignore; } public void setContextName(String name) { interceptor.setContextName(name); } public void setLoginConfig(Configuration config) { interceptor.setLoginConfig(config); } public void setRoleClassifier(String rc) { interceptor.setRoleClassifier(rc); } public void setRoleClassifierType(String rct) { interceptor.setRoleClassifierType(rct); } public void setRedirectURI(String uri) { this.redirectURI = URI.create(uri); } public void setRealmName(String name) { this.realmName = name; } protected CallbackHandler getCallbackHandler(String name, String password) { return new NamePasswordCallbackHandler(name, password); } @Override public void filter(ContainerRequestContext context) { Message m = JAXRSUtils.getCurrentMessage(); try { interceptor.handleMessage(m); } catch (AuthenticationException ex) { context.abortWith(handleAuthenticationException(ex, m)); } catch (SecurityException ex) { context.abortWith(handleAuthenticationException(ex, m)); } } protected Response handleAuthenticationException(SecurityException ex, Message m) { HttpHeaders headers = new HttpHeadersImpl(m); if (redirectURI != null && isRedirectPossible(headers)) { URI finalRedirectURI = null; if (!redirectURI.isAbsolute()) { String endpointAddress = HttpUtils.getEndpointAddress(m); Object basePathProperty = m.get(Message.BASE_PATH); if (ignoreBasePath && basePathProperty != null && !"/".equals(basePathProperty)) { int index = endpointAddress.lastIndexOf(basePathProperty.toString()); if (index != -1) { endpointAddress = endpointAddress.substring(0, index); } } finalRedirectURI = UriBuilder.fromUri(endpointAddress).path(redirectURI.toString()).build(); } else { finalRedirectURI = redirectURI; } return Response.status(getRedirectStatus()). header(HttpHeaders.LOCATION, finalRedirectURI).build(); } else { ResponseBuilder builder = Response.status(Response.Status.UNAUTHORIZED); StringBuilder sb = new StringBuilder(); List<String> authHeader = headers.getRequestHeader(HttpHeaders.AUTHORIZATION); if (authHeader != null && !authHeader.isEmpty()) { // should HttpHeadersImpl do it ? String[] authValues = StringUtils.split(authHeader.get(0), " "); if (authValues.length > 0) { sb.append(authValues[0]); } } else { sb.append("Basic"); } if (realmName != null) { sb.append(" realm=\"").append(realmName).append('"'); } builder.header(HttpHeaders.WWW_AUTHENTICATE, sb.toString()); return builder.build(); } } protected Response.Status getRedirectStatus() { return Response.Status.TEMPORARY_REDIRECT; } protected boolean isRedirectPossible(HttpHeaders headers) { List<MediaType> clientTypes = headers.getAcceptableMediaTypes(); return !JAXRSUtils.intersectMimeTypes(clientTypes, HTML_MEDIA_TYPES, false) .isEmpty(); } }