blob: fc6ed546f2d6c68b85365a16fd5dbc682db77b84 [file] [log] [blame]
package org.apache.archiva.redback.rest.services.v2;
/*
* 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.
*/
import org.apache.archiva.redback.authentication.AuthenticationConstants;
import org.apache.archiva.redback.authentication.AuthenticationException;
import org.apache.archiva.redback.authentication.AuthenticationFailureCause;
import org.apache.archiva.redback.authentication.PasswordBasedAuthenticationDataSource;
import org.apache.archiva.redback.authentication.Token;
import org.apache.archiva.redback.authentication.TokenType;
import org.apache.archiva.redback.authentication.jwt.JwtAuthenticator;
import org.apache.archiva.redback.authentication.jwt.TokenAuthenticationException;
import org.apache.archiva.redback.integration.filter.authentication.HttpAuthenticator;
import org.apache.archiva.redback.policy.AccountLockedException;
import org.apache.archiva.redback.policy.MustChangePasswordException;
import org.apache.archiva.redback.rest.api.model.ErrorMessage;
import org.apache.archiva.redback.rest.api.model.GrantType;
import org.apache.archiva.redback.rest.api.model.PingResult;
import org.apache.archiva.redback.rest.api.model.TokenRequest;
import org.apache.archiva.redback.rest.api.model.RequestTokenRequest;
import org.apache.archiva.redback.rest.api.model.TokenResponse;
import org.apache.archiva.redback.rest.api.model.User;
import org.apache.archiva.redback.rest.api.model.UserLogin;
import org.apache.archiva.redback.rest.api.services.RedbackServiceException;
import org.apache.archiva.redback.rest.api.services.v2.AuthenticationService;
import org.apache.archiva.redback.system.SecuritySession;
import org.apache.archiva.redback.system.SecuritySystem;
import org.apache.archiva.redback.users.UserManagerException;
import org.apache.archiva.redback.users.UserNotFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
*
* Authentication service provides REST methods for authentication and verification.
*
* @author Olivier Lamy
* @author Martin Stockhammer
* @since 3.0
*/
@Service( "v2.authenticationService#rest" )
public class DefaultAuthenticationService
implements AuthenticationService
{
private static final Logger log = LoggerFactory.getLogger( DefaultAuthenticationService.class );
private SecuritySystem securitySystem;
private HttpAuthenticator httpAuthenticator;
@Context
private HttpServletRequest httpServletRequest;
@Context
private HttpServletResponse response;
@Inject
private JwtAuthenticator jwtAuthenticator;
// validation token lifetime: 3 hours
long tokenLifetime = 1000*3600*3;
@Inject
public DefaultAuthenticationService( SecuritySystem securitySystem,
@Named( "httpAuthenticator#basic" ) HttpAuthenticator httpAuthenticator )
{
this.securitySystem = securitySystem;
this.httpAuthenticator = httpAuthenticator;
}
@Override
public PingResult ping()
{
return new PingResult( true);
}
@Override
public PingResult pingWithAutz()
{
return new PingResult( true );
}
@Override
public TokenResponse logIn( RequestTokenRequest loginRequest )
throws RedbackServiceException
{
if (!GrantType.AUTHORIZATION_CODE.equals(loginRequest.getGrantType())) {
throw new RedbackServiceException( "redback:bad_authorization_code", Response.Status.FORBIDDEN.getStatusCode( ) );
}
String userName = loginRequest.getUserId(), password = loginRequest.getPassword();
PasswordBasedAuthenticationDataSource authDataSource =
new PasswordBasedAuthenticationDataSource( userName, password );
log.debug("Login for {}",userName);
try
{
SecuritySession securitySession = securitySystem.authenticate( authDataSource );
log.debug("Security session {}", securitySession);
if ( securitySession.getAuthenticationResult() != null
&& securitySession.getAuthenticationResult().isAuthenticated() )
{
org.apache.archiva.redback.users.User user = securitySession.getUser();
org.apache.archiva.redback.authentication.Token token = jwtAuthenticator.generateToken( user.getUsername( ) );
log.debug("User {} authenticated", user.getUsername());
if ( !user.isValidated() )
{
log.info( "user {} not validated", user.getUsername() );
throw new RedbackServiceException( "redback:user-not-validated", Response.Status.FORBIDDEN.getStatusCode() );
}
// Stateless services no session
// httpAuthenticator.authenticate( authDataSource, httpServletRequest.getSession( true ) );
org.apache.archiva.redback.authentication.Token refreshToken = jwtAuthenticator.generateToken( user.getUsername( ), TokenType.REFRESH_TOKEN );
response.setHeader( "Cache-Control", "no-store" );
response.setHeader( "Pragma", "no-cache" );
return new TokenResponse(token, refreshToken, "", loginRequest.getState());
} else if ( securitySession.getAuthenticationResult() != null
&& securitySession.getAuthenticationResult().getAuthenticationFailureCauses() != null )
{
List<ErrorMessage> errorMessages = new ArrayList<ErrorMessage>();
for ( AuthenticationFailureCause authenticationFailureCause : securitySession.getAuthenticationResult().getAuthenticationFailureCauses() )
{
if ( authenticationFailureCause.getCause() == AuthenticationConstants.AUTHN_NO_SUCH_USER )
{
errorMessages.add( new ErrorMessage( "redback:incorrect.username.password" ) );
}
else
{
errorMessages.add( new ErrorMessage().message( "redback:"+authenticationFailureCause.getMessage() ) );
}
}
response.setHeader( "WWW-Authenticate", "redback-login realm="+httpServletRequest.getRemoteHost() );
throw new RedbackServiceException( errorMessages , Response.Status.UNAUTHORIZED.getStatusCode());
}
response.setHeader( "WWW-Authenticate", "redback-login realm="+httpServletRequest.getRemoteHost() );
throw new RedbackServiceException( "redback:login-failed", Response.Status.UNAUTHORIZED.getStatusCode() );
}
catch ( AuthenticationException e )
{
log.debug( "Authentication error: {}", e.getMessage( ), e );
throw new RedbackServiceException( "redback:login-failed", Response.Status.UNAUTHORIZED.getStatusCode() );
}
catch ( UserNotFoundException e )
{
log.debug( "User not found: {}", e.getMessage( ), e );
throw new RedbackServiceException( "redback:login-failed", Response.Status.UNAUTHORIZED.getStatusCode() );
}
catch (AccountLockedException e) {
log.info( "Account locked: {}", e.getMessage( ), e );
throw new RedbackServiceException( "redback:account-locked", Response.Status.FORBIDDEN.getStatusCode() );
}
catch ( MustChangePasswordException e )
{
log.debug( "Password change required: {}", e.getMessage( ), e );
throw new RedbackServiceException( "redback:password-change-required", Response.Status.FORBIDDEN.getStatusCode( ) );
}
catch ( UserManagerException e )
{
log.warn( "UserManagerException: {}", e.getMessage() );
List<ErrorMessage> errorMessages =
Arrays.asList( new ErrorMessage().message( "UserManagerException: " + e.getMessage() ) );
throw new RedbackServiceException( errorMessages );
}
}
@Override
public TokenResponse token( TokenRequest request ) throws RedbackServiceException
{
if (!GrantType.REFRESH_TOKEN.equals(request.getGrantType())) {
log.debug( "Bad grant type {}, expected: refresh_token", request.getGrantType( ).name( ).toLowerCase( ) );
throw new RedbackServiceException( "redback:bad_grant", Response.Status.FORBIDDEN.getStatusCode( ) );
}
try
{
Token accessToken = jwtAuthenticator.refreshAccessToken( request.getRefreshToken( ) );
Token refreshToken = jwtAuthenticator.tokenFromString( request.getRefreshToken( ) );
response.setHeader( "Cache-Control", "no-store" );
response.setHeader( "Pragma", "no-cache" );
return new TokenResponse( accessToken, refreshToken );
}
catch ( TokenAuthenticationException e )
{
throw new RedbackServiceException( e.getError( ).getError( ), Response.Status.UNAUTHORIZED.getStatusCode( ) );
}
}
@Override
public User getAuthenticatedUser()
throws RedbackServiceException
{
SecuritySession securitySession = httpAuthenticator.getSecuritySession( httpServletRequest.getSession( true ) );
Boolean isLogged = securitySession != null;
log.debug( "isLogged {}", isLogged );
return isLogged && securitySession.getUser() != null ? buildRestUser( securitySession.getUser() ) : null;
}
private UserLogin buildRestUser( org.apache.archiva.redback.users.User user )
{
UserLogin restUser = new UserLogin();
restUser.setEmail( user.getEmail() );
restUser.setUsername( user.getUsername() );
restUser.setPasswordChangeRequired( user.isPasswordChangeRequired() );
restUser.setLocked( user.isLocked() );
restUser.setValidated( user.isValidated() );
restUser.setFullName( user.getFullName() );
return restUser;
}
}