This project has retired. For details please refer to its Attic page.
ArchivaUserManagerAuthenticator xref
View Javadoc
1   package org.apache.archiva.web.security;
2   /*
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   * http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   */
20  
21  import org.apache.archiva.admin.model.RepositoryAdminException;
22  import org.apache.archiva.admin.model.runtime.RedbackRuntimeConfigurationAdmin;
23  import org.apache.archiva.metadata.model.facets.AuditEvent;
24  import org.apache.archiva.redback.authentication.AbstractAuthenticator;
25  import org.apache.archiva.redback.authentication.AuthenticationConstants;
26  import org.apache.archiva.redback.authentication.AuthenticationDataSource;
27  import org.apache.archiva.redback.authentication.AuthenticationException;
28  import org.apache.archiva.redback.authentication.AuthenticationFailureCause;
29  import org.apache.archiva.redback.authentication.AuthenticationResult;
30  import org.apache.archiva.redback.authentication.Authenticator;
31  import org.apache.archiva.redback.authentication.PasswordBasedAuthenticationDataSource;
32  import org.apache.archiva.redback.policy.AccountLockedException;
33  import org.apache.archiva.redback.policy.MustChangePasswordException;
34  import org.apache.archiva.redback.policy.PasswordEncoder;
35  import org.apache.archiva.redback.policy.UserSecurityPolicy;
36  import org.apache.archiva.redback.users.User;
37  import org.apache.archiva.redback.users.UserManager;
38  import org.apache.archiva.redback.users.UserNotFoundException;
39  import org.apache.archiva.repository.events.AuditListener;
40  import org.apache.archiva.rest.services.interceptors.AuditInfoFilter;
41  import org.slf4j.Logger;
42  import org.slf4j.LoggerFactory;
43  import org.springframework.context.ApplicationContext;
44  import org.springframework.stereotype.Service;
45  
46  import javax.annotation.PostConstruct;
47  import javax.inject.Inject;
48  import java.util.ArrayList;
49  import java.util.List;
50  
51  /**
52   * @author Olivier Lamy
53   * @since 1.4-M4
54   */
55  @Service("authenticator#archiva")
56  public class ArchivaUserManagerAuthenticator
57      extends AbstractAuthenticator
58      implements Authenticator
59  {
60      private Logger log = LoggerFactory.getLogger( getClass() );
61  
62      @Inject
63      private UserSecurityPolicy securityPolicy;
64  
65      @Inject
66      private ApplicationContext applicationContext;
67  
68      @Inject
69      private RedbackRuntimeConfigurationAdmin redbackRuntimeConfigurationAdmin;
70  
71      @Inject
72      private List<AuditListener> auditListeners = new ArrayList<>();
73  
74      private List<UserManager> userManagers;
75  
76      private boolean valid = false;
77  
78      @PostConstruct
79      @Override
80      public void initialize()
81          throws AuthenticationException
82      {
83          try
84          {
85              List<String> userManagerImpls =
86                  redbackRuntimeConfigurationAdmin.getRedbackRuntimeConfiguration().getUserManagerImpls();
87  
88              userManagers = new ArrayList<>( userManagerImpls.size() );
89  
90              for ( String beanId : userManagerImpls )
91              {
92                  userManagers.add( applicationContext.getBean( "userManager#" + beanId, UserManager.class ) );
93              }
94              valid=true;
95          }
96          catch ( RepositoryAdminException e )
97          {
98              log.error("Error during repository initialization "+e.getMessage(),e);
99              // throw new AuthenticationException( e.getMessage(), e );
100         }
101     }
102 
103     protected AuditInfoFilter.AuditInfo getAuditInformation()
104     {
105         return AuditInfoFilter.getAuditInfo( );
106     }
107 
108     public List<AuditListener> getAuditListeners()
109     {
110         return auditListeners;
111     }
112 
113     protected void triggerAuditEvent( String repositoryId, String filePath, String action, String user )
114     {
115         AuditEvent auditEvent = new AuditEvent( repositoryId, user, filePath, action );
116         AuditInfoFilter.AuditInfo auditInformation = getAuditInformation();
117         auditEvent.setUserId( user );
118         auditEvent.setRemoteIP( auditInformation.getRemoteHost() + ":" + auditInformation.getRemotePort() );
119         for ( AuditListener auditListener : getAuditListeners() )
120         {
121             auditListener.auditEvent( auditEvent );
122         }
123     }
124 
125     @Override
126     public AuthenticationResult authenticate( AuthenticationDataSource ds )
127         throws AuthenticationException, AccountLockedException, MustChangePasswordException
128     {
129         boolean authenticationSuccess = false;
130         String username = null;
131         Exception resultException = null;
132         PasswordBasedAuthenticationDataSource source = (PasswordBasedAuthenticationDataSource) ds;
133         List<AuthenticationFailureCause> authnResultErrors = new ArrayList<>();
134         final String loginUserId = source.getUsername( );
135 
136         for ( UserManager userManager : userManagers )
137         {
138             try
139             {
140                 log.debug( "Authenticate: {} with userManager: {}", source, userManager.getId() );
141                 User user = userManager.findUser( loginUserId );
142                 username = user.getUsername();
143 
144                 if ( user.isLocked() )
145                 {
146                     //throw new AccountLockedException( "Account " + source.getUsername() + " is locked.", user );
147                     AccountLockedException e =
148                         new AccountLockedException( "Account " + loginUserId + " is locked.", user );
149                     log.warn( "{}", e.getMessage() );
150                     triggerAuditEvent( "", "", "login-account-locked", loginUserId );
151                     resultException = e;
152                     authnResultErrors.add(
153                         new AuthenticationFailureCause( AuthenticationConstants.AUTHN_LOCKED_USER_EXCEPTION,
154                                                         e.getMessage() ) );
155                 }
156 
157                 if ( user.isPasswordChangeRequired() && source.isEnforcePasswordChange() )
158                 {
159                     //throw new MustChangePasswordException( "Password expired.", user );
160                     MustChangePasswordException e = new MustChangePasswordException( "Password expired.", user );
161                     log.warn( "{}", e.getMessage() );
162                     resultException = e;
163                     triggerAuditEvent( "", "", "login-password-change-required", loginUserId );
164                     authnResultErrors.add(
165                         new AuthenticationFailureCause( AuthenticationConstants.AUTHN_MUST_CHANGE_PASSWORD_EXCEPTION,
166                                                         e.getMessage() ) );
167                 }
168 
169                 PasswordEncoder encoder = securityPolicy.getPasswordEncoder();
170                 log.debug( "PasswordEncoder: {}", encoder.getClass().getName() );
171 
172                 boolean isPasswordValid = encoder.isPasswordValid( user.getEncodedPassword(), source.getPassword() );
173                 if ( isPasswordValid )
174                 {
175                     log.debug( "User {} provided a valid password", loginUserId );
176 
177                     try
178                     {
179                         securityPolicy.extensionPasswordExpiration( user );
180 
181                         authenticationSuccess = true;
182                         triggerAuditEvent( "", "", "login-success", loginUserId );
183 
184 
185                         //REDBACK-151 do not make unnessesary updates to the user object
186                         if ( user.getCountFailedLoginAttempts() > 0 )
187                         {
188                             user.setCountFailedLoginAttempts( 0 );
189                             if ( !userManager.isReadOnly() )
190                             {
191                                 userManager.updateUser( user );
192                             }
193                         }
194 
195                         return new AuthenticationResult( true, loginUserId, null );
196                     }
197                     catch ( MustChangePasswordException e )
198                     {
199                         user.setPasswordChangeRequired( true );
200                         triggerAuditEvent( "", "", "login-password-change-required", loginUserId );
201                         //throw e;
202                         resultException = e;
203                         authnResultErrors.add( new AuthenticationFailureCause(
204                             AuthenticationConstants.AUTHN_MUST_CHANGE_PASSWORD_EXCEPTION, e.getMessage() ).user( user ) );
205                     }
206                 }
207                 else
208                 {
209                     log.warn( "Password is Invalid for user {} and userManager '{}'.", source.getUsername(),
210                               userManager.getId() );
211                     triggerAuditEvent( "", "", "login-authentication-failed", loginUserId );
212 
213                     authnResultErrors.add( new AuthenticationFailureCause( AuthenticationConstants.AUTHN_NO_SUCH_USER,
214                                                                            "Password is Invalid for user "
215                                                                                + source.getUsername() + "." ).user( user ) );
216 
217                     try
218                     {
219 
220                         securityPolicy.extensionExcessiveLoginAttempts( user );
221 
222                     }
223                     finally
224                     {
225                         if ( !userManager.isReadOnly() )
226                         {
227                             userManager.updateUser( user );
228                         }
229                     }
230 
231                     //return new AuthenticationResult( false, source.getUsername(), null, authnResultExceptionsMap );
232                 }
233             }
234             catch ( UserNotFoundException e )
235             {
236                 log.warn( "Login for user {} and userManager {} failed. user not found.", loginUserId,
237                           userManager.getId() );
238                 resultException = e;
239                 triggerAuditEvent( "", "", "login-user-unknown", loginUserId );
240                 authnResultErrors.add( new AuthenticationFailureCause( AuthenticationConstants.AUTHN_NO_SUCH_USER,
241                                                                        "Login for user " + source.getUsername()
242                                                                            + " failed. user not found." ) );
243             }
244             catch ( Exception e )
245             {
246                 log.warn( "Login for user {} and userManager {} failed, message: {}", loginUserId,
247                           userManager.getId(), e.getMessage() );
248                 resultException = e;
249                 triggerAuditEvent( "", "", "login-error", loginUserId );
250                 authnResultErrors.add( new AuthenticationFailureCause( AuthenticationConstants.AUTHN_RUNTIME_EXCEPTION,
251                                                                        "Login for user " + source.getUsername()
252                                                                            + " failed, message: " + e.getMessage() ) );
253             }
254         }
255         return new AuthenticationResult( authenticationSuccess, username, resultException, authnResultErrors );
256     }
257 
258     @Override
259     public boolean supportsDataSource( AuthenticationDataSource source )
260     {
261         return ( source instanceof PasswordBasedAuthenticationDataSource );
262     }
263 
264     @Override
265     public String getId()
266     {
267         return "ArchivaUserManagerAuthenticator";
268     }
269 
270     public boolean isValid() {
271         return valid;
272     }
273 }