Class ShibAuthentication

java.lang.Object
org.dspace.authenticate.ShibAuthentication
All Implemented Interfaces:
AuthenticationMethod

public class ShibAuthentication extends Object implements AuthenticationMethod
Shibboleth authentication for DSpace Shibboleth is a distributed authentication system for securely authenticating users and passing attributes about the user from one or more identity providers. In the Shibboleth terminology DSpace is a Service Provider which receives authentication information and then based upon that provides a service to the user. With Shibboleth DSpace will require that you use Apache installed with the mod_shib module acting as a proxy for all HTTP requests for your servlet container (typically Tomcat). DSpace will receive authentication information from the mod_shib module through HTTP headers. See for more information on installing and configuring a Shibboleth Service Provider: https://wiki.shibboleth.net/confluence/display/SHIB2/Installation See the DSpace.cfg or DSpace manual for information on how to configure this authentication module.
Author:
Bruc Liong, MELCOE, Xiang Kevin Li, MELCOE, Scott Phillips
  • Field Details

  • Constructor Details

    • ShibAuthentication

      public ShibAuthentication()
  • Method Details

    • authenticate

      public int authenticate(Context context, String username, String password, String realm, jakarta.servlet.http.HttpServletRequest request) throws SQLException
      Authenticate the given or implicit credentials. This is the heart of the authentication method: test the credentials for authenticity, and if accepted, attempt to match (or optionally, create) an EPerson. If an EPerson is found it is set in the Context that was passed. DSpace supports authentication using NetID, or email address. A user's NetID is a unique identifier from the IdP that identifies a particular user. The NetID can be of almost any form such as a unique integer, string, or with Shibboleth 2.0 you can use "targeted ids". You will need to coordinate with your Shibboleth federation or identity provider. There are three ways to supply identity information to DSpace: 1) NetID from Shibboleth Header (best) The NetID-based method is superior because users may change their email address with the identity provider. When this happens DSpace will not be able to associate their new address with their old account. 2) Email address from Shibboleth Header (okay) In the case where a NetID header is not available or not found DSpace will fall back to identifying a user based-upon their email address. 3) Tomcat's Remote User (worst) In the event that neither Shibboleth headers are found then as a last resort DSpace will look at Tomcat's remote user field. This is the least attractive option because Tomcat has no way to supply additional attributes about a user. Because of this the autoregister option is not supported if this method is used. Identity Scheme Migration Strategies: If you are currently using Email based authentication (either 1 or 2) and want to upgrade to NetID based authentication then there is an easy path. Simply enable Shibboleth to pass the NetID attribute and set the netid-header below to the correct value. When a user attempts to log in to DSpace first DSpace will look for an EPerson with the passed NetID, however when this fails DSpace will fall back to email based authentication. Then DSpace will update the user's EPerson account record to set their netid so all future authentications for this user will be based upon netid. One thing to note is that DSpace will prevent an account from switching NetIDs. If an account already has a NetID set and then they try and authenticate with a different NetID the authentication will fail.
      Specified by:
      authenticate in interface AuthenticationMethod
      Parameters:
      context - DSpace context, will be modified (ePerson set) upon success.
      username - Username (or email address) when method is explicit. Use null for implicit method.
      password - Password for explicit auth, or null for implicit method.
      realm - Not used by Shibboleth-based authentication
      request - The HTTP request that started this operation, or null if not applicable.
      Returns:
      One of: SUCCESS, BAD_CREDENTIALS, CERT_REQUIRED, NO_SUCH_USER, BAD_ARGS

      Meaning:
      SUCCESS - authenticated OK.
      BAD_CREDENTIALS - user exists, but credentials (e.g. passwd) don't match
      CERT_REQUIRED - not allowed to login this way without X.509 cert.
      NO_SUCH_USER - user not found using this method.
      BAD_ARGS - user/pw not appropriate for this method

      Throws:
      SQLException - if database error
    • getSpecialGroups

      public List<Group> getSpecialGroups(Context context, jakarta.servlet.http.HttpServletRequest request)
      Get list of extra groups that user implicitly belongs to. Note that this method will be invoked regardless of the authentication status of the user (logged-in or not) e.g. a group that depends on the client network-address. DSpace is able to place users into pre-defined groups based upon values received from Shibboleth. Using this option you can place all faculty members into a DSpace group when the correct affiliation's attribute is provided. When DSpace does this they are considered 'special groups', these are really groups but the user's membership within these groups is not recorded in the database. Each time a user authenticates they are automatically placed within the pre-defined DSpace group, so if the user loses their affiliation then the next time they login they will no longer be in the group. Depending upon the shibboleth attributed use in the role-header, it may be scoped. Scoped is shibboleth terminology for identifying where an attribute originated from. For example a students affiliation may be encoded as "student@tamu.edu". The part after the @ sign is the scope, and the preceding value is the value. You may use the whole value or only the value or scope. Using this you could generate a role for students and one institution different than students at another institution. Or if you turn on ignore-scope you could ignore the institution and place all students into one group. The values extracted (a user may have multiple roles) will be used to look up which groups to place the user into. The groups are defined as authentication.shib.role.<role-name> which is a comma separated list of DSpace groups.
      Specified by:
      getSpecialGroups in interface AuthenticationMethod
      Parameters:
      context - A valid DSpace context.
      request - The request that started this operation, or null if not applicable.
      Returns:
      array of EPerson-group IDs, possibly 0-length, but never null.
    • allowSetPassword

      public boolean allowSetPassword(Context context, jakarta.servlet.http.HttpServletRequest request, String email) throws SQLException
      Indicate whether or not a particular self-registering user can set themselves a password in the profile info form.
      Specified by:
      allowSetPassword in interface AuthenticationMethod
      Parameters:
      context - DSpace context
      request - HTTP request, in case anything in that is used to decide
      email - e-mail address of user attempting to register
      Returns:
      true if this method allows user to change ePerson password.
      Throws:
      SQLException - if database error
    • isImplicit

      public boolean isImplicit()
      Predicate, is this an implicit authentication method. An implicit method gets credentials from the environment (such as an HTTP request or even Java system properties) rather than the explicit username and password. For example, a method that reads the X.509 certificates in an HTTPS request is implicit.
      Specified by:
      isImplicit in interface AuthenticationMethod
      Returns:
      true if this method uses implicit authentication.
    • canSelfRegister

      public boolean canSelfRegister(Context context, jakarta.servlet.http.HttpServletRequest request, String username) throws SQLException
      Indicate whether or not a particular user can self-register, based on e-mail address.
      Specified by:
      canSelfRegister in interface AuthenticationMethod
      Parameters:
      context - DSpace context
      request - HTTP request, in case anything in that is used to decide
      username - e-mail address of user attempting to register
      Returns:
      true if new ePerson should be created.
      Throws:
      SQLException - if database error
    • initEPerson

      public void initEPerson(Context context, jakarta.servlet.http.HttpServletRequest request, EPerson eperson) throws SQLException
      Initialize a new e-person record for a self-registered new user.
      Specified by:
      initEPerson in interface AuthenticationMethod
      Parameters:
      context - DSpace context
      request - HTTP request, in case it's needed
      eperson - newly created EPerson record - email + information from the registration form will have been filled out.
      Throws:
      SQLException - if database error
    • loginPageURL

      public String loginPageURL(Context context, jakarta.servlet.http.HttpServletRequest request, jakarta.servlet.http.HttpServletResponse response)
      Get login page to which to redirect. Returns URL (as string) to which to redirect to obtain credentials (either password prompt or e.g. HTTPS port for client cert.); null means no redirect.

      For Shibboleth, this URL looks like (note 'target' param is URL encoded, but shown as unencoded in this example) [shibURL]?target=[dspace.server.url]/api/authn/shibboleth?redirectUrl=[dspace.ui.url]

      This URL is used by the client to redirect directly to Shibboleth for authentication. The "target" param is then the location (in REST API) where Shibboleth redirects back to. The "redirectUrl" is the path/URL in the client (e.g. Angular UI) which the REST API redirects the user to (after capturing/storing any auth info from Shibboleth).

      Specified by:
      loginPageURL in interface AuthenticationMethod
      Parameters:
      context - DSpace context, will be modified (ePerson set) upon success.
      request - The HTTP request that started this operation, or null if not applicable.
      response - The HTTP response from the servlet method.
      Returns:
      fully-qualified URL or null
    • getName

      public String getName()
      Description copied from interface: AuthenticationMethod
      Returns a short name that uniquely identifies this authentication method
      Specified by:
      getName in interface AuthenticationMethod
      Returns:
      The authentication method name
    • isEnabled

      public static boolean isEnabled()
      Check if Shibboleth plugin is enabled
      Returns:
      true if enabled, false otherwise
    • findEPerson

      protected EPerson findEPerson(Context context, jakarta.servlet.http.HttpServletRequest request) throws SQLException, AuthorizeException
      Identify an existing EPerson based upon the shibboleth attributes provided on the request object. There are three cases where this can occur, each as a fallback for the previous method. 1) NetID from Shibboleth Header (best) The NetID-based method is superior because users may change their email address with the identity provider. When this happens DSpace will not be able to associate their new address with their old account. 2) Email address from Shibboleth Header (okay) In the case where a NetID header is not available or not found DSpace will fall back to identifying a user based upon their email address. 3) Tomcat's Remote User (worst) In the event that neither Shibboleth headers are found then as a last resort DSpace will look at Tomcat's remote user field. This is the least attractive option because Tomcat has no way to supply additional attributes about a user. Because of this the autoregister option is not supported if this method is used. If successful then the identified EPerson will be returned, otherwise null.
      Parameters:
      context - The DSpace database context
      request - The current HTTP Request
      Returns:
      The EPerson identified or null.
      Throws:
      SQLException - if database error
      AuthorizeException - if authorization error
    • registerNewEPerson

      protected EPerson registerNewEPerson(Context context, jakarta.servlet.http.HttpServletRequest request) throws SQLException, AuthorizeException
      Register a new eperson object. This method is called when no existing user was found for the NetID or Email and autoregister is enabled. When these conditions are met this method will create a new eperson object. In order to create a new eperson object there is a minimal set of metadata required: Email, First Name, and Last Name. If we don't have access to these three pieces of information then we will be unable to create a new eperson object, such as the case when Tomcat's Remote User field is used to identify a particular user. Note, that this method only adds the minimal metadata. Any additional metadata will need to be added by the updateEPerson method.
      Parameters:
      context - The current DSpace database context
      request - The current HTTP Request
      Returns:
      A new eperson object or null if unable to create a new eperson.
      Throws:
      SQLException - if database error
      AuthorizeException - if authorization error
    • updateEPerson

      protected void updateEPerson(Context context, jakarta.servlet.http.HttpServletRequest request, EPerson eperson) throws SQLException, AuthorizeException
      After we successfully authenticated a user, this method will update the user's attributes. The user's email, name, or other attribute may have been changed since the last time they logged into DSpace. This method will update the database with their most recent information. This method handles the basic DSpace metadata (email, first name, last name) along with additional metadata set using the setMetadata() methods on the eperson object. The additional metadata are defined by a mapping created in the dspace.cfg.
      Parameters:
      context - The current DSpace database context
      request - The current HTTP Request
      eperson - The eperson object to update.
      Throws:
      SQLException - if database error
      AuthorizeException - if authorization error
    • swordCompatibility

      protected int swordCompatibility(Context context, String username, String password, jakarta.servlet.http.HttpServletRequest request) throws SQLException
      Provide password-based authentication to enable sword compatibility. Sword compatibility will allow this authentication method to work when using sword. Sword relies on username and password based authentication and is entirely incapable of supporting shibboleth. This option allows you to authenticate username and passwords for sword sessions without adding another authentication method onto the stack. You will need to ensure that a user has a password. One way to do that is to create the user via the create-administrator command line command and then edit their permissions.
      Parameters:
      context - The DSpace database context
      username - The username
      password - The password
      request - The HTTP Request
      Returns:
      A valid DSpace Authentication Method status code.
      Throws:
      SQLException - if database error
    • initialize

      protected void initialize(Context context) throws SQLException
      Initialize Shibboleth Authentication. During initialization the mapping of additional eperson metadata will be loaded from the DSpace.cfg and cached. While loading the metadata mapping this method will check the EPerson object to see if it supports the metadata field. If the field is not supported and autocreate is turned on then the field will be automatically created. It is safe to call this methods multiple times.
      Parameters:
      context - context
      Throws:
      SQLException - if database error
    • checkIfEpersonMetadataFieldExists

      protected boolean checkIfEpersonMetadataFieldExists(Context context, String metadataName) throws SQLException
      Check if a MetadataField for an eperson is available.
      Parameters:
      metadataName - The name of the metadata field.
      context - context
      Returns:
      True if a valid metadata field, otherwise false.
      Throws:
      SQLException - if database error
    • autoCreateEpersonMetadataField

      protected boolean autoCreateEpersonMetadataField(Context context, String metadataName) throws SQLException
      Automatically create a new metadataField for an eperson
      Parameters:
      context - context
      metadataName - The name of the new metadata field.
      Returns:
      True if successful, otherwise false.
      Throws:
      SQLException - if database error
    • findAttribute

      protected String findAttribute(jakarta.servlet.http.HttpServletRequest request, String name)
      Find a particular Shibboleth header value and return the all values. The header name uses a bit of fuzzy logic, so it will first try case sensitive, then it will try lowercase, and finally it will try uppercase. This method will not interpret the header value in any way. This method will return null if value is empty.
      Parameters:
      request - The HTTP request to look for values in.
      name - The name of the attribute or header
      Returns:
      The value of the attribute or header requested, or null if none found.
    • findSingleAttribute

      protected String findSingleAttribute(jakarta.servlet.http.HttpServletRequest request, String name)
      Find a particular Shibboleth header value and return the first value. The header name uses a bit of fuzzy logic, so it will first try case sensitive, then it will try lowercase, and finally it will try uppercase. Shibboleth attributes may contain multiple values separated by a semicolon. This method will return the first value in the attribute. If you need multiple values use findMultipleAttributes instead. If no attribute is found then null is returned.
      Parameters:
      request - The HTTP request to look for headers values on.
      name - The name of the header
      Returns:
      The value of the header requested, or null if none found.
    • findMultipleAttributes

      protected List<String> findMultipleAttributes(jakarta.servlet.http.HttpServletRequest request, String name)
      Find a particular Shibboleth hattributeeader value and return the values. The attribute name uses a bit of fuzzy logic, so it will first try case sensitive, then it will try lowercase, and finally it will try uppercase. Shibboleth attributes may contain multiple values separated by a semicolon and semicolons are escaped with a backslash. This method will split all the attributes into a list and unescape semicolons. If no attributes are found then null is returned.
      Parameters:
      request - The HTTP request to look for headers values on.
      name - The name of the attribute
      Returns:
      The list of values found, or null if none found.
    • isUsed

      public boolean isUsed(Context context, jakarta.servlet.http.HttpServletRequest request)
      Description copied from interface: AuthenticationMethod
      Get whether the authentication method is being used.
      Specified by:
      isUsed in interface AuthenticationMethod
      Parameters:
      context - The DSpace context
      request - The current request
      Returns:
      whether the authentication method is being used.
    • canChangePassword

      public boolean canChangePassword(Context context, EPerson ePerson, String currentPassword)
      Description copied from interface: AuthenticationMethod
      Check if the given current password is valid to change the password of the given ePerson
      Specified by:
      canChangePassword in interface AuthenticationMethod
      Parameters:
      context - The DSpace context
      ePerson - the ePerson related to the password change
      currentPassword - The current password to check
      Returns:
      true if the provided password matches with current password