Changeset 6423


Ignore:
Timestamp:
Feb 25, 2014, 1:11:25 PM (9 years ago)
Author:
Nicklas Nordborg
Message:

References #1599: Convert authentication plug-in system to an extension point

Created extension point for authentication. Extensions should implement the AuthenticationAction interface. The old Authenticator interface is deprecated but it should not be difficult to convert existing authenticators to the new system. Login information is now sent using LoginRequest object via the AuthenticationContext object.

Location:
trunk/src/core
Files:
3 added
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/core/core-extensions.xml

    r6079 r6423  
    3737    <url>http://base.thep.lu.se/</url>
    3838  </about>
     39 
     40  <extension-point
     41    id="net.sf.basedb.core.authentication-manager"
     42    >
     43    <action-class>net.sf.basedb.core.authentication.AuthenticationManager</action-class>
     44    <name>Authentication manager</name>
     45    <description>
     46      Extension point for authentication of users when logging in to BASE.
     47      Installed authentication managers are invoked in the index order.
     48      An authentication manager have three possible options:
     49      1) Decide that the login/password is valid and return an
     50         AuthenticationInformation object. No further authentication managers
     51         are invoked and the user is logged in to BASE.
     52      2) Decide that the login/password is invalid and throw an
     53         Exception. No further authentication managers
     54         are invoked and the user is NOT logged in to BASE.
     55      3) Decide that it doesn't know if the login/password is valid or not
     56         and return null. The next authentication manager is invoked.
     57         If this was the last authentication manager, internal authentication
     58         is used.
     59    </description>
     60  </extension-point>
    3961 
    4062  <extension-point
  • trunk/src/core/net/sf/basedb/core/Application.java

    r6127 r6423  
    2727import net.sf.basedb.core.data.SchemaVersionData;
    2828import net.sf.basedb.core.hibernate.JdbcWork;
    29 import net.sf.basedb.core.authentication.Authenticator;
    30 import net.sf.basedb.util.ClassUtil;
    3129import net.sf.basedb.util.EmailUtil;
    3230import net.sf.basedb.util.FileUtil;
    33 import net.sf.basedb.util.JarClassLoader;
    3431import net.sf.basedb.util.RegexpFileFilter;
    3532import net.sf.basedb.util.StaticCache;
     
    9390    The name of the external authenication class, if any.
    9491  */
    95   private static String authenticationDriver;
     92  //private static String authenticationDriver;
    9693 
    9794  /**
     
    425422     
    426423      Config.init();
    427       authenticationDriver = Config.getString("auth.driver");
    428       log.info("auth.driver = " + authenticationDriver);
     424      //authenticationDriver = Config.getString("auth.driver");
     425      //log.info("auth.driver = " + authenticationDriver);
    429426     
    430427      secondaryStorageDriver = Config.getString("secondary.storage.driver");
     
    703700  /**
    704701    Check if BASE is using internal or external authentication.
    705     @return TRUE if internal authentication is used, FALSE otherwise
     702    @return Always true
    706703    @see #getAuthenticator()
    707   */
     704    @deprecated In 3.3, no replacement
     705  */
     706  @Deprecated
    708707  public static boolean isUsingInternalAuthentication()
    709708  {
    710     return authenticationDriver == null;
     709    return true;
    711710  }
    712711
     
    715714    authentication. The authenticator is initialised before it is returned.
    716715    If internal authentication is used, this method returns null.
    717     @return An <code>Authenticator</code> object, or null if
    718       not using external authentication
     716    @return Always null
    719717    @throws BaseException If the authenticator class could not be loaded
    720718    @see #isUsingInternalAuthentication()
    721   */
    722   static Authenticator getAuthenticator()
     719    @deprecated In 3.3, no replacement
     720  */
     721  @Deprecated
     722  static net.sf.basedb.core.authentication.Authenticator getAuthenticator()
    723723    throws BaseException
    724724  {
    725     if (isUsingInternalAuthentication()) return null;
    726     Authenticator a;
    727     try
    728     {
    729       String jarPath = net.sf.basedb.util.Values.getStringOrNull(Config.getString("auth.jarpath"));
    730       ClassLoader loader = jarPath == null ? null : JarClassLoader.getInstance(jarPath);
    731       a = (Authenticator)ClassUtil.checkAndLoadClass(loader,
    732         authenticationDriver, true, Authenticator.class).newInstance();
    733       a.init(Config.getString("auth.init"));
    734     }
    735     catch (Throwable t)
    736     {
    737       throw new BaseException("The authentication driver '"+authenticationDriver+
    738         "' could not be loaded. The error message is: "+t.getMessage());
    739     }
    740     return a;
     725    return null;
    741726  }
    742727
  • trunk/src/core/net/sf/basedb/core/SessionControl.java

    r6127 r6423  
    4242import net.sf.basedb.core.data.ContextIndex;
    4343import net.sf.basedb.util.Enumeration;
    44 
    45 import net.sf.basedb.core.authentication.Authenticator;
     44import net.sf.basedb.util.extensions.ExtensionsInvoker;
     45import net.sf.basedb.util.extensions.Registry;
     46import net.sf.basedb.util.extensions.manager.ExtensionsManager;
     47import net.sf.basedb.core.authentication.AuthenticationManager;
    4648import net.sf.basedb.core.authentication.AuthenticationInformation;
     49import net.sf.basedb.core.authentication.LoginRequest;
    4750
    4851import java.util.ArrayList;
     
    326329    loginInfo = li;
    327330  }
     331 
     332  /**
     333    @deprecated In 3.3, use {@link #login(LoginRequest)} instead
     334  */
     335  @Deprecated
     336  public synchronized void login(String login, String password, String comment)
     337  {
     338    LoginRequest loginRequest = new LoginRequest();
     339    loginRequest.setLogin(login);
     340    loginRequest.setPassword(password);
     341    loginRequest.setComment(comment);
     342    login(loginRequest);
     343  }
    328344
    329345  /**
     
    332348    the client application if one has been specified.
    333349
    334     @param login The login of the user
    335     @param password The UTF-8 encoded plain-text password for the user
    336     @param comment A comment for the login, which will show in the {@link Session}
     350    @param loginRequest Request containing login/password and other information
    337351    @throws ItemNotFoundException If a user with the specified username is not found
    338352    @throws InvalidPasswordException If the specified password is incorrect
     
    344358    @see #isLoggedIn()
    345359    @see #getLoggedInUserId()
    346     @since 3.0 (the option to use encrypted passwords has been removed)
    347   */
    348   public synchronized void login(String login, String password, String comment)
    349     throws ItemNotFoundException, PermissionDeniedException,
    350     InvalidPasswordException, BaseException
     360    @since 3.3
     361  */
     362  public synchronized void login(LoginRequest loginRequest)
    351363  {
    352364    updateLastAccess();
     
    356368      throw new AlreadyLoggedInException(loginInfo.userLogin);
    357369    }
    358     if (login == null) throw new InvalidUseOfNullException("login");
    359     if (password == null) throw new InvalidUseOfNullException("password");
     370    if (loginRequest == null) throw new InvalidUseOfNullException("loginRequest");
     371    if (loginRequest.getLogin() == null) throw new InvalidUseOfNullException("loginRequest.login");
    360372
    361373    org.hibernate.Session session = null;
     
    365377      session = HibernateUtil.newSession();
    366378      tx = HibernateUtil.newTransaction(session);
    367       // Verify login and password
     379
    368380      UserData userData = null;
    369       // The root user should always use internal verification
     381      // Try external authentication at first, except...
     382      // ...root user should always use internal verification
    370383      UserData root = HibernateUtil.loadData(session, UserData.class, SystemItems.getId(User.ROOT));
    371384      assert root != null : "root == null";
    372       if (Application.isUsingInternalAuthentication() || login.equals(root.getLogin()))
    373       {
    374         userData = verifyUserInternal(session, login, password);
    375       }
    376       else
    377       {
    378         userData = verifyUserExternal(session, login, password);
    379       }
    380       LoginInfo li = createLoginInfo(session, userData, comment, false);
     385     
     386      if (!loginRequest.getLogin().equals(root.getLogin()))
     387      {
     388        userData = verifyUserExternal(session, loginRequest);
     389      }
     390     
     391      if (userData == null)
     392      {
     393        // If no user was found, use internal authentication
     394        userData = verifyUserInternal(session, loginRequest);
     395      }
     396     
     397      LoginInfo li = createLoginInfo(session, userData, loginRequest.getComment(), false);
    381398      HibernateUtil.commit(tx);
    382399      currentContexts.clear();
     
    394411  }
    395412 
    396   /**
    397     Check that the user exists and verify the password using
    398     internal authentication.
    399   */
    400   private UserData verifyUserInternal(org.hibernate.Session session, String login, String password)
    401     throws ItemNotFoundException, InvalidPasswordException, AccountExpiredException, BaseException
    402   {
     413
     414  /**
     415    Verify the user with internal authentication.
     416  */
     417  UserData verifyUserInternal(org.hibernate.Session session, LoginRequest loginRequest)
     418  {
     419    String login = loginRequest.getLogin();
     420    String password = loginRequest.getPassword();
     421   
    403422    org.hibernate.Query query = HibernateUtil.getPredefinedQuery(session, "GET_USER_FOR_LOGIN");
    404423    /*
     
    433452      throw new InvalidPasswordException("User[login="+login+"]");
    434453    }
     454   
    435455    return userData;
    436456  }
    437 
     457 
    438458  /**
    439459    Verify the user with external authentication.
    440460  */
    441   private UserData verifyUserExternal(org.hibernate.Session session, String login, String password)
    442     throws ItemNotFoundException, InvalidPasswordException, BaseException
    443   {
     461  @SuppressWarnings("unchecked")
     462  private UserData verifyUserExternal(org.hibernate.Session session, LoginRequest loginRequest)
     463  {
     464    AuthenticationContext context = new AuthenticationContext(this, session, loginRequest);
     465   
     466    ExtensionsManager xtManager = Application.getExtensionsManager();
     467    Registry registry = xtManager.getRegistry();
     468    ExtensionsInvoker<AuthenticationManager> invoker = (ExtensionsInvoker<AuthenticationManager>)registry.useExtensions(context, xtManager.getSettings(), "net.sf.basedb.core.authentication-manager");
     469   
    444470    AuthenticationInformation info = null;
    445     Authenticator authenticator = null;
     471    boolean extraInfo = false;
    446472    try
    447473    {
    448       authenticator = Application.getAuthenticator();
    449       info = authenticator.authenticate(login, password);
     474      // Load all installed authentication managers and iterate until
     475      // someone returns an info object or throws an exception
     476      for (AuthenticationManager auth : invoker)
     477      {
     478        info = auth.authenticate();
     479        if (info != null)
     480        {
     481          // Found a valid login
     482          extraInfo = auth.supportsExtraInformation() && info.hasExtraInfo;
     483          break;
     484        }
     485      }
    450486    }
    451487    catch (net.sf.basedb.core.authentication.LoginException ex)
     
    455491    catch (net.sf.basedb.core.authentication.UnknownLoginException ex)
    456492    {
    457       throw new ItemNotFoundException("User[login="+login+"]", ex);
     493      throw new ItemNotFoundException("User[login="+loginRequest.getLogin()+"]", ex);
    458494    }
    459495    catch (net.sf.basedb.core.authentication.InvalidPasswordException ex)
    460496    {
    461       throw new InvalidPasswordException("User[login="+login+"]", ex);
     497      throw new InvalidPasswordException("User[login="+loginRequest.getLogin()+"]", ex);
    462498    }
    463499    catch (net.sf.basedb.core.authentication.AuthenticationException ex)
    464500    {
    465       if (Config.getBoolean("auth.cachepasswords"))
    466       {
    467         return verifyUserInternal(session, login, password);
    468       }
    469       throw new BaseException(ex);
    470     }
    471 
    472     org.hibernate.Query query = HibernateUtil.getPredefinedQuery(session, "GET_USER_FOR_EXTERNAL_ID");
    473     /*
    474       SELECT usr
    475       FROM UserData usr
    476       WHERE usr.externalId = :externalId
    477     */
    478     query.setParameter("externalId", info.id);
    479     UserData userData = HibernateUtil.loadData(UserData.class, query);
     501      if (!Config.getBoolean("auth.cachepasswords"))
     502      {
     503        throw new BaseException(ex);
     504      }
     505    }
     506   
     507    // Return null to force internal verification
     508    if (info == null) return null;
     509
     510    UserData userData = context.getUserByExternalId(info.id);
    480511    if (userData == null)
    481512    {
     513      // Create new user
    482514      userData = new UserData();
    483515      userData.setExternalId(info.id);
     
    487519      User.addDefultRolesAndGroups(session, userData);
    488520    }
     521   
     522    // Cache the password if allowed by config
    489523    if (Config.getBoolean("auth.cachepasswords"))
    490524    {
    491       userData.getPassword().setCryptedPassword(User.encryptPassword(password));
     525      userData.getPassword().setCryptedPassword(User.encryptPassword(loginRequest.getPassword()));
    492526      int daysToCache = Config.getInt("auth.daystocache", 0);
    493527      userData.setExpirationDate(daysToCache > 0 ? new Date(System.currentTimeMillis()+daysToCache*24L*3600L*1000L) : null);
    494528    }
    495     if (authenticator.supportsExtraInformation() &&
    496       (Config.getBoolean("auth.synchronize") || userData.getId() == 0))
     529   
     530    // Synchronize extra information if supported and allowed by config
     531    if (extraInfo && (Config.getBoolean("auth.synchronize") || userData.getId() == 0))
    497532    {
    498533      userData.setName(info.name == null ? info.login : info.name);
  • trunk/src/core/net/sf/basedb/core/authentication/AuthenticationException.java

    r5822 r6423  
    3232*/
    3333public class AuthenticationException
    34   extends Exception
     34  extends RuntimeException
    3535
    3636{
  • trunk/src/core/net/sf/basedb/core/authentication/AuthenticationInformation.java

    r4889 r6423  
    4141public class AuthenticationInformation
    4242{
     43  /**
     44    TRUE if the contructor with extra information was used, FALSE if the minial constructor was used.
     45    @since 3.3
     46  */
     47  public final boolean hasExtraInfo;
     48 
    4349  /**
    4450    A unique id for the user in the authentication system.
     
    100106  public AuthenticationInformation(String login, String id)
    101107  {
    102     this(login, id, null, null, null, null, null, null, null, null);
     108    this(login, id, null, null, null, null, null, null, null, null, false);
    103109  }
    104110
     
    132138  )
    133139  {
     140    this(login, id, name, organisation, address, phone, fax, email, url, description, true);
     141  }
     142 
     143  private AuthenticationInformation
     144  (
     145    String login,
     146    String id,
     147    String name,
     148    String organisation,
     149    String address,
     150    String phone,
     151    String fax,
     152    String email,
     153    String url,
     154    String description,
     155    boolean hasExtraInfo
     156  )
     157  {
    134158    if (id == null) throw new NullPointerException("id");
    135159    if (login == null) throw new NullPointerException("login");
     
    144168    this.url = url;
    145169    this.description = description;
     170    this.hasExtraInfo = hasExtraInfo;
    146171  }
    147172
  • trunk/src/core/net/sf/basedb/core/authentication/Authenticator.java

    r4889 r6423  
    3131  @version 2.0
    3232  @base.modified $Date$
     33  @deprecated In 3.3, use {@link AuthenticationManager} instead
    3334*/
     35@Deprecated
    3436public interface Authenticator
    3537{
  • trunk/src/core/net/sf/basedb/core/authentication/POP3Authenticator.java

    r6127 r6423  
    5050  @version 2.0
    5151  @base.modified $Date$
     52  @deprecated In 3.3, no replacement
    5253*/
     54@Deprecated
    5355public class POP3Authenticator
    5456  implements Authenticator
  • trunk/src/core/net/sf/basedb/core/authentication/SimpleAuthenticator.java

    r6127 r6423  
    3333  @version 2.0
    3434  @base.modified $Date$
     35  @deprecated In 3.3, no replacement
    3536*/
     37@Deprecated
    3638public class SimpleAuthenticator
    3739  implements Authenticator
  • trunk/src/core/net/sf/basedb/util/extensions/debug/BeanActionFactory.java

    r5946 r6423  
    168168      // Set parameters on the bean
    169169      actions = new Action[] { bean };
    170       for (Map.Entry<String, String> entry : parameters.entrySet())
     170      if (parameters != null)
    171171      {
    172         String name = entry.getKey();
    173         String value = entry.getValue();
    174        
    175         // Find a setParam() method. Ignore parameter if not found
    176         Method setter = findSetterMethod(name, bean.getClass());           
    177         if (setter == null)
     172        for (Map.Entry<String, String> entry : parameters.entrySet())
    178173        {
    179           /* #### CONTINUE-STATEMENT #### */
    180           continue;
     174          String name = entry.getKey();
     175          String value = entry.getValue();
     176         
     177          // Find a setParam() method. Ignore parameter if not found
     178          Method setter = findSetterMethod(name, bean.getClass());           
     179          if (setter == null)
     180          {
     181            /* #### CONTINUE-STATEMENT #### */
     182            continue;
     183          }
     184         
     185          // Convert value to correct type for setParam(T) method
     186          Object o = convertValue(value, setter.getParameterTypes()[0]);
     187          try
     188          {
     189            setter.invoke(bean, o);
     190          }
     191          catch (IllegalAccessException ex)
     192          {}
     193          catch (InvocationTargetException ex)
     194          {}
    181195        }
    182        
    183         // Convert value to correct type for setParam(T) method
    184         Object o = convertValue(value, setter.getParameterTypes()[0]);
    185         try
    186         {
    187           setter.invoke(bean, o);
    188         }
    189         catch (IllegalAccessException ex)
    190         {}
    191         catch (InvocationTargetException ex)
    192         {}
    193196      }
    194197    }
  • trunk/src/core/net/sf/basedb/util/extensions/debug/ProxyActionFactory.java

    r5946 r6423  
    226226      value = valueCache.get(parameterName);
    227227    }
    228     else
     228    else if (parameters != null)
    229229    {
    230230      // Get the string value from the XML file
Note: See TracChangeset for help on using the changeset viewer.