| 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; |
| } |
| } |