001package org.apache.archiva.redback.rest.services.interceptors;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022
023import org.apache.archiva.redback.authentication.AuthenticationException;
024import org.apache.archiva.redback.authentication.AuthenticationResult;
025import org.apache.archiva.redback.authorization.RedbackAuthorization;
026import org.apache.archiva.redback.integration.filter.authentication.HttpAuthenticationException;
027import org.apache.archiva.redback.integration.filter.authentication.basic.HttpBasicAuthentication;
028import org.apache.archiva.redback.policy.AccountLockedException;
029import org.apache.archiva.redback.policy.MustChangePasswordException;
030import org.apache.archiva.redback.rest.services.RedbackAuthenticationThreadLocal;
031import org.apache.archiva.redback.rest.services.RedbackRequestInformation;
032import org.apache.archiva.redback.system.SecuritySession;
033import org.apache.archiva.redback.users.User;
034import org.apache.archiva.redback.users.UserManager;
035import org.apache.archiva.redback.users.UserManagerException;
036import org.apache.archiva.redback.users.UserNotFoundException;
037import org.slf4j.Logger;
038import org.slf4j.LoggerFactory;
039import org.springframework.stereotype.Service;
040
041import javax.annotation.Priority;
042import javax.inject.Inject;
043import javax.inject.Named;
044import javax.servlet.http.HttpServletRequest;
045import javax.servlet.http.HttpServletResponse;
046import javax.ws.rs.container.ContainerRequestContext;
047import javax.ws.rs.container.ContainerRequestFilter;
048import javax.ws.rs.container.ResourceInfo;
049import javax.ws.rs.core.Context;
050import javax.ws.rs.core.Response;
051import javax.ws.rs.ext.Provider;
052
053/**
054 * This interceptor will check if the user is already logged in the session.
055 * If not ask the redback system to authentication trough BASIC http
056 * If the user is logged the AuthenticationResult will in the cxf message with the key AuthenticationResult.class
057 *
058 * @author Olivier Lamy
059 * @since 1.3
060 */
061@Service("authenticationInterceptor#rest")
062@Provider
063@Priority( Priorities.AUTHENTICATION )
064public class AuthenticationInterceptor
065    extends AbstractInterceptor
066    implements ContainerRequestFilter
067{
068    @Inject
069    @Named(value = "userManager#default")
070    private UserManager userManager;
071
072    @Inject
073    @Named(value = "httpAuthenticator#basic")
074    private HttpBasicAuthentication httpAuthenticator;
075
076    @Context
077    private ResourceInfo resourceInfo;
078
079    private final Logger log = LoggerFactory.getLogger( getClass() );
080
081    public void filter( ContainerRequestContext containerRequestContext )
082    {
083
084        // Message message = JAXRSUtils.getCurrentMessage();
085
086        RedbackAuthorization redbackAuthorization = getRedbackAuthorization( resourceInfo );
087        if ( redbackAuthorization == null )
088        {
089            log.warn( "http path {} doesn't contain any informations regarding permissions ",
090                      containerRequestContext.getUriInfo().getRequestUri());
091            // here we failed to authenticate so 403 as there is no detail on karma for this
092            // it must be marked as it's exposed
093            containerRequestContext.abortWith( Response.status( Response.Status.FORBIDDEN ).build() );
094            return;
095        }
096        HttpServletRequest request = getHttpServletRequest( );
097        HttpServletResponse response = getHttpServletResponse( );
098
099        if ( redbackAuthorization.noRestriction() )
100        {
101            // maybe session exists so put it in threadLocal
102            // some services need the current user if logged
103            SecuritySession securitySession = httpAuthenticator.getSecuritySession( request.getSession( true ) );
104
105            if ( securitySession != null )
106            {
107                RedbackRequestInformation redbackRequestInformation =
108                    new RedbackRequestInformation( securitySession.getUser(), request.getRemoteAddr() );
109                RedbackAuthenticationThreadLocal.set( redbackRequestInformation );
110            }
111            else
112            {
113                // maybe there is some authz in the request so try it but not fail so catch Exception !
114                try
115                {
116                    AuthenticationResult authenticationResult =
117                        httpAuthenticator.getAuthenticationResult( request, response );
118
119                    if ( ( authenticationResult == null ) || ( !authenticationResult.isAuthenticated() ) )
120                    {
121                        return;
122                    }
123
124                    User user = authenticationResult.getUser() == null ? userManager.findUser(
125                        authenticationResult.getPrincipal() ) : authenticationResult.getUser();
126                    RedbackRequestInformation redbackRequestInformation =
127                        new RedbackRequestInformation( user, request.getRemoteAddr() );
128
129                    RedbackAuthenticationThreadLocal.set( redbackRequestInformation );
130                    // message.put( AuthenticationResult.class, authenticationResult );
131                    containerRequestContext.setProperty( AUTHENTICATION_RESULT, authenticationResult );
132                }
133                catch ( Exception e )
134                {
135                    // ignore here
136                }
137            }
138            return;
139        }
140
141        try
142        {
143            AuthenticationResult authenticationResult = httpAuthenticator.getAuthenticationResult( request, response );
144
145            if ( ( authenticationResult == null ) || ( !authenticationResult.isAuthenticated() ) )
146            {
147                throw new HttpAuthenticationException( "You are not authenticated." );
148            }
149
150            User user = authenticationResult.getUser() == null
151                ? userManager.findUser( authenticationResult.getPrincipal() )
152                : authenticationResult.getUser();
153
154            RedbackRequestInformation redbackRequestInformation =
155                new RedbackRequestInformation( user, request.getRemoteAddr() );
156
157            RedbackAuthenticationThreadLocal.set( redbackRequestInformation );
158            // message.put( AuthenticationResult.class, authenticationResult );
159
160            return;
161        }
162        catch ( UserNotFoundException e )
163        {
164            log.debug( "UserNotFoundException for path {}", containerRequestContext.getUriInfo().getRequestUri() );
165        }
166        catch ( AccountLockedException e )
167        {
168            log.debug( "account locked for path {}", containerRequestContext.getUriInfo().getRequestUri() );
169        }
170        catch ( MustChangePasswordException e )
171        {
172            log.debug( "must change password for path {}", containerRequestContext.getUriInfo().getRequestUri() );
173        }
174        catch ( AuthenticationException e )
175        {
176            log.debug( "failed to authenticate for path {}", containerRequestContext.getUriInfo().getRequestUri() );
177        }
178        catch ( UserManagerException e )
179        {
180            log.debug( "UserManagerException: {} for path", e.getMessage(), containerRequestContext.getUriInfo().getRequestUri() );
181        }
182        containerRequestContext.abortWith( Response.status( Response.Status.FORBIDDEN ).build() );
183    }
184}