mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-18 07:23:08 +00:00
DS-1012: updated the configuration parameters to use the modules syntax instead of the old style all in one.
git-svn-id: http://scm.dspace.org/svn/repo/dspace/trunk@6915 9c30dcfa-912a-0410-8fc2-9e0234be79fd
This commit is contained in:
@@ -165,7 +165,7 @@ public class ShibAuthentication implements AuthenticationMethod
|
|||||||
// sword. This allows this compatability without installing the password-based
|
// sword. This allows this compatability without installing the password-based
|
||||||
// authentication method which has side effects such as allowing users to login
|
// authentication method which has side effects such as allowing users to login
|
||||||
// with a username and password from the webui.
|
// with a username and password from the webui.
|
||||||
boolean swordCompatability = ConfigurationManager.getBooleanProperty("authentication.shib.sword.compatability", true);
|
boolean swordCompatability = ConfigurationManager.getBooleanProperty("authentication-shibboleth","sword.compatability", true);
|
||||||
if ( swordCompatability &&
|
if ( swordCompatability &&
|
||||||
username != null && username.length() > 0 &&
|
username != null && username.length() > 0 &&
|
||||||
password != null && password.length() > 0 ) {
|
password != null && password.length() > 0 ) {
|
||||||
@@ -199,7 +199,7 @@ public class ShibAuthentication implements AuthenticationMethod
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Should we auto register new users.
|
// Should we auto register new users.
|
||||||
boolean autoRegister = ConfigurationManager.getBooleanProperty("authentication.shib.autoregister", true);
|
boolean autoRegister = ConfigurationManager.getBooleanProperty("authentication-shibboleth","autoregister", true);
|
||||||
|
|
||||||
// Four steps to authenticate a user
|
// Four steps to authenticate a user
|
||||||
try {
|
try {
|
||||||
@@ -291,10 +291,10 @@ public class ShibAuthentication implements AuthenticationMethod
|
|||||||
}
|
}
|
||||||
|
|
||||||
log.debug("Starting to determine special groups");
|
log.debug("Starting to determine special groups");
|
||||||
String defaultRoles = ConfigurationManager.getProperty("authentication.shib.default-roles");
|
String defaultRoles = ConfigurationManager.getProperty("authentication-shibboleth","default-roles");
|
||||||
String roleHeader = ConfigurationManager.getProperty("authentication.shib.role-header");
|
String roleHeader = ConfigurationManager.getProperty("authentication-shibboleth","role-header");
|
||||||
boolean ignoreScope = ConfigurationManager.getBooleanProperty("authentication.shib.role-header.ignore-scope", true);
|
boolean ignoreScope = ConfigurationManager.getBooleanProperty("authentication-shibboleth","role-header.ignore-scope", true);
|
||||||
boolean ignoreValue = ConfigurationManager.getBooleanProperty("authentication.shib.role-header.ignore-value", false);
|
boolean ignoreValue = ConfigurationManager.getBooleanProperty("authentication-shibboleth","role-header.ignore-value", false);
|
||||||
|
|
||||||
if (ignoreScope && ignoreValue) {
|
if (ignoreScope && ignoreValue) {
|
||||||
throw new IllegalStateException("Both config parameters for ignoring an roll attributes scope and value are turned on, this is not a permissable configuration. (Note: ignore-scope defaults to true) The configuration parameters are: 'authentication.shib.role-header.ignore-scope' and 'authentication.shib.role-header.ignore-value'");
|
throw new IllegalStateException("Both config parameters for ignoring an roll attributes scope and value are turned on, this is not a permissable configuration. (Note: ignore-scope defaults to true) The configuration parameters are: 'authentication.shib.role-header.ignore-scope' and 'authentication.shib.role-header.ignore-value'");
|
||||||
@@ -330,9 +330,9 @@ public class ShibAuthentication implements AuthenticationMethod
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the group names
|
// Get the group names
|
||||||
String groupNames = ConfigurationManager.getProperty("authentication.shib.role." + affiliation);
|
String groupNames = ConfigurationManager.getProperty("authentication-shibboleth","role." + affiliation);
|
||||||
if (groupNames == null || groupNames.trim().length() == 0) {
|
if (groupNames == null || groupNames.trim().length() == 0) {
|
||||||
groupNames = ConfigurationManager.getProperty("authentication.shib.role." + affiliation.toLowerCase());
|
groupNames = ConfigurationManager.getProperty("authentication-shibboleth","role." + affiliation.toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (groupNames == null) {
|
if (groupNames == null) {
|
||||||
@@ -473,11 +473,11 @@ public class ShibAuthentication implements AuthenticationMethod
|
|||||||
// If this server is configured for lazy sessions then use this to
|
// If this server is configured for lazy sessions then use this to
|
||||||
// login, otherwise default to the protected shibboleth url.
|
// login, otherwise default to the protected shibboleth url.
|
||||||
|
|
||||||
boolean lazySession = ConfigurationManager.getBooleanProperty("authentication.shib.lazysession", false);
|
boolean lazySession = ConfigurationManager.getBooleanProperty("authentication-shibboleth","lazysession", false);
|
||||||
|
|
||||||
if ( lazySession ) {
|
if ( lazySession ) {
|
||||||
String shibURL = ConfigurationManager.getProperty("authentication.shib.lazysession.loginurl");
|
String shibURL = ConfigurationManager.getProperty("authentication-shibboleth","lazysession.loginurl");
|
||||||
boolean forceHTTPS = ConfigurationManager.getBooleanProperty("authentication.shib.lazysession.secure",true);
|
boolean forceHTTPS = ConfigurationManager.getBooleanProperty("authentication-shibboleth","lazysession.secure",true);
|
||||||
|
|
||||||
// Shibboleth authentication initiator
|
// Shibboleth authentication initiator
|
||||||
if (shibURL == null || shibURL.length() == 0)
|
if (shibURL == null || shibURL.length() == 0)
|
||||||
@@ -565,9 +565,9 @@ public class ShibAuthentication implements AuthenticationMethod
|
|||||||
*/
|
*/
|
||||||
private EPerson findEPerson(Context context, HttpServletRequest request) throws SQLException, AuthorizeException {
|
private EPerson findEPerson(Context context, HttpServletRequest request) throws SQLException, AuthorizeException {
|
||||||
|
|
||||||
boolean isUsingTomcatUser = ConfigurationManager.getBooleanProperty("authentication.shib.email-use-tomcat-remote-user");
|
boolean isUsingTomcatUser = ConfigurationManager.getBooleanProperty("authentication-shibboleth","email-use-tomcat-remote-user");
|
||||||
String netidHeader = ConfigurationManager.getProperty("authentication.shib.netid-header");
|
String netidHeader = ConfigurationManager.getProperty("authentication-shibboleth","netid-header");
|
||||||
String emailHeader = ConfigurationManager.getProperty("authentication.shib.email-header");
|
String emailHeader = ConfigurationManager.getProperty("authentication-shibboleth","email-header");
|
||||||
|
|
||||||
EPerson eperson = null;
|
EPerson eperson = null;
|
||||||
boolean foundNetID = false;
|
boolean foundNetID = false;
|
||||||
@@ -664,10 +664,10 @@ public class ShibAuthentication implements AuthenticationMethod
|
|||||||
private EPerson registerNewEPerson(Context context, HttpServletRequest request) throws SQLException, AuthorizeException {
|
private EPerson registerNewEPerson(Context context, HttpServletRequest request) throws SQLException, AuthorizeException {
|
||||||
|
|
||||||
// Header names
|
// Header names
|
||||||
String netidHeader = ConfigurationManager.getProperty("authentication.shib.netid-header");
|
String netidHeader = ConfigurationManager.getProperty("authentication-shibboleth","netid-header");
|
||||||
String emailHeader = ConfigurationManager.getProperty("authentication.shib.email-header");
|
String emailHeader = ConfigurationManager.getProperty("authentication-shibboleth","email-header");
|
||||||
String fnameHeader = ConfigurationManager.getProperty("authentication.shib.firstname-header");
|
String fnameHeader = ConfigurationManager.getProperty("authentication-shibboleth","firstname-header");
|
||||||
String lnameHeader = ConfigurationManager.getProperty("authentication.shib.lastname-header");
|
String lnameHeader = ConfigurationManager.getProperty("authentication-shibboleth","lastname-header");
|
||||||
|
|
||||||
// Header values
|
// Header values
|
||||||
String netid = findSingleHeader(request,netidHeader);
|
String netid = findSingleHeader(request,netidHeader);
|
||||||
@@ -751,10 +751,10 @@ public class ShibAuthentication implements AuthenticationMethod
|
|||||||
private void updateEPerson(Context context, HttpServletRequest request, EPerson eperson) throws SQLException, AuthorizeException {
|
private void updateEPerson(Context context, HttpServletRequest request, EPerson eperson) throws SQLException, AuthorizeException {
|
||||||
|
|
||||||
// Header names & values
|
// Header names & values
|
||||||
String netidHeader = ConfigurationManager.getProperty("authentication.shib.netid-header");
|
String netidHeader = ConfigurationManager.getProperty("authentication-shibboleth","netid-header");
|
||||||
String emailHeader = ConfigurationManager.getProperty("authentication.shib.email-header");
|
String emailHeader = ConfigurationManager.getProperty("authentication-shibboleth","email-header");
|
||||||
String fnameHeader = ConfigurationManager.getProperty("authentication.shib.firstname-header");
|
String fnameHeader = ConfigurationManager.getProperty("authentication-shibboleth","firstname-header");
|
||||||
String lnameHeader = ConfigurationManager.getProperty("authentication.shib.lastname-header");
|
String lnameHeader = ConfigurationManager.getProperty("authentication-shibboleth","lastname-header");
|
||||||
|
|
||||||
String netid = findSingleHeader(request,netidHeader);
|
String netid = findSingleHeader(request,netidHeader);
|
||||||
String email = findSingleHeader(request,emailHeader);
|
String email = findSingleHeader(request,emailHeader);
|
||||||
@@ -897,8 +897,8 @@ public class ShibAuthentication implements AuthenticationMethod
|
|||||||
|
|
||||||
HashMap<String, String> map = new HashMap<String,String>();
|
HashMap<String, String> map = new HashMap<String,String>();
|
||||||
|
|
||||||
String mappingString = ConfigurationManager.getProperty("authentication.shib.eperson.metadata");
|
String mappingString = ConfigurationManager.getProperty("authentication-shibboleth","eperson.metadata");
|
||||||
boolean autoCreate = ConfigurationManager.getBooleanProperty("authentication.shib.eperson.metadata.autocreate", true);
|
boolean autoCreate = ConfigurationManager.getBooleanProperty("authentication-shibboleth","eperson.metadata.autocreate", true);
|
||||||
|
|
||||||
// Bail out if not set, returning an empty map.
|
// Bail out if not set, returning an empty map.
|
||||||
if (mappingString == null || mappingString.trim().length() == 0) {
|
if (mappingString == null || mappingString.trim().length() == 0) {
|
||||||
|
@@ -4,79 +4,176 @@
|
|||||||
# Configuration properties used by the Shibboleth #
|
# Configuration properties used by the Shibboleth #
|
||||||
# Authentication plugin, when it is enabled. #
|
# Authentication plugin, when it is enabled. #
|
||||||
#---------------------------------------------------------------#
|
#---------------------------------------------------------------#
|
||||||
|
#### Shibboleth Authentication Configuration Settings ####
|
||||||
|
# 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.
|
||||||
#
|
#
|
||||||
# In order to enable Shibboleth Authentication, you must first ensure the
|
# See for more information on installing and configuring a Shibboleth
|
||||||
# 'org.dspace.authenticate.ShibAuthentication' class is added to the
|
# Service Provider:
|
||||||
# list of enabled AuthenticationMethods in 'authenticate.cfg'.
|
# https://wiki.shibboleth.net/confluence/display/SHIB2/Installation
|
||||||
# See 'authenticate.cfg' for more info.
|
|
||||||
|
|
||||||
|
##
|
||||||
|
## Shibboleth Sessions:
|
||||||
|
##
|
||||||
|
# When configuring your Shibboleth Service Provider there are two paradigms you
|
||||||
|
# may use: Active or Lazy Sessions. Active sessions is where the mob_shib
|
||||||
|
# module is configured to product a URL space. No one will be able to access
|
||||||
|
# that URL without first authenticating with Shibboleth. Using this method you
|
||||||
|
# will need to configure shibboleth to protect the URL: "/shibboleth-login".
|
||||||
|
# The alternative, Lazy Session does not protect any specific URL. Instead
|
||||||
|
# apache will allow access to any URL, and when the application wants to it
|
||||||
|
# may initiate an authenticated session. The Lazy Session method is preferable
|
||||||
|
# for most DSpace installations where you want public access to most of DSpace
|
||||||
|
# but restricted access to limitted areas - such as administration.
|
||||||
|
|
||||||
|
# Whether to use lazy sessions or active sessions.
|
||||||
|
lazysession = true
|
||||||
|
|
||||||
|
# The url to start a shibboleth session (only for lazy sessions)
|
||||||
|
lazysession.loginurl = /Shibboleth.sso/Login
|
||||||
|
|
||||||
|
# Force HTTPS when authenticating (only for lazy sessions)
|
||||||
|
lazysession.secure = true
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
## Shibboleth Authentication Methods:
|
||||||
|
##
|
||||||
|
# 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:
|
||||||
#
|
#
|
||||||
# Check https://mams.melcoe.mq.edu.au/zope/mams/pubs/Installation/dspace15/view
|
# 1) NetID from Shibboleth Header (best)
|
||||||
# for installation detail.
|
|
||||||
#
|
#
|
||||||
# DSpace requires email as user's credential. There are 2 ways of providing
|
# The NetID-based method is superior because users may change their email
|
||||||
# email to DSpace:
|
# address with the identity provider. When this happens DSpace will not be
|
||||||
# 1) by explicitly specifying to the user which attribute (header)
|
# able to associate their new address with their old account.
|
||||||
# carries the email address.
|
#
|
||||||
# 2) by turning on the user-email-using-tomcat=true which means
|
# 2) Email address from Shibboleth Header (okay)
|
||||||
# the software will try to acquire the user's email from Tomcat
|
#
|
||||||
# The first option takes PRECEDENCE when specified. Both options can
|
# In the case where a NetID header is not available or not found DSpace
|
||||||
# be enabled to allow fallback.
|
# 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 netted so all future
|
||||||
|
# authentications for this user will be based upon netted. One thing to note
|
||||||
|
# is that DSpace will prevent an account from switching NetIDs. If an account
|
||||||
|
# all ready has a NetID set and then they try and authenticate with a
|
||||||
|
# different NetID the authentication will fail.
|
||||||
|
|
||||||
# this option below specifies that the email comes from the mentioned header.
|
# Authentication headers for Mail, NetID, and Tomcat's Remote User.
|
||||||
# The value is CASE-Sensitive.
|
# Supply all parameters possible.
|
||||||
email-header = MAIL
|
netid-header = SHIB-NETID
|
||||||
|
email-header = SHIB-MAIL
|
||||||
|
email-use-tomcat-remote-user = false
|
||||||
|
|
||||||
# optional. Specify the header that carries user's first name
|
# Should we allow new users to be registered automatically?
|
||||||
# this is going to be used for creation of new-user
|
|
||||||
firstname-header = SHIB-EP-GIVENNAME
|
|
||||||
|
|
||||||
# optional. Specify the header that carries user's last name
|
|
||||||
# this is used for creation of new user
|
|
||||||
lastname-header = SHIB-EP-SURNAME
|
|
||||||
|
|
||||||
# this option below forces the software to acquire the email from Tomcat.
|
|
||||||
email-use-tomcat-remote-user = true
|
|
||||||
|
|
||||||
# should we allow new users to be registered automtically
|
|
||||||
# if the IdP provides sufficient info (and user not exists in DSpace)
|
|
||||||
autoregister = true
|
autoregister = true
|
||||||
|
|
||||||
# these two header here specify which attribute that is responsible
|
# Sword compatability will allow this authentication method to work when using
|
||||||
# for providing user's roles to DSpace and unscope the attributes if needed.
|
# sword. Sort relies on username and password based authentication and is
|
||||||
# When not specified, it is defaulted to 'Shib-EP-UnscopedAffiliation', and
|
# entirely incapable of supporting shibboleth. This option allows you to
|
||||||
# ignore-scope is defaulted to 'false'.
|
# authenticate username and passwords for sword sessions with out adding
|
||||||
# The value is specified in AAP.xml (Shib 1.3.x) or
|
# another authentication method onto the stack. You will need to ensure that
|
||||||
# attribute-filter.xml (Shib 2.x). The value is CASE-Sensitive.
|
# a user has a password. One way to do that is to create the user via the
|
||||||
# The values provided in this header are separated by semi-colon or comma.
|
# create-administrator command line command and then edit their permissions.
|
||||||
# If your sp only provides scoped role header, you need to set
|
sword.compatability = false
|
||||||
# role-header.ignore-Scope as true.
|
|
||||||
# for example if you only get Shib-EP-ScopedAffiliation instead of Shib-EP-ScopedAffiliation,
|
|
||||||
# you have to make your setting as:
|
|
||||||
# role-header = Shib-EP-ScopedAffiliation
|
|
||||||
# role-header.ignore-scope = true
|
|
||||||
|
|
||||||
# role-header = Shib-EP-UnscopedAffiliation
|
|
||||||
role-header.ignore-scope = false
|
|
||||||
|
|
||||||
# when user is fully authN on IdP but would not like to release
|
##
|
||||||
# his/her roles to DSpace (for privacy reason?), what should be
|
## EPerson Metadata:
|
||||||
# the default roles be given to such users?
|
##
|
||||||
# The values are separated by semi-colon or comma
|
# One of the primary benefits of using Shibboleth based authentication is
|
||||||
# default-roles = Staff, Walk-ins
|
# receiving additional attributes about users such as their names, telephone
|
||||||
|
# numbers, and possibly their academic department or graduation semester if
|
||||||
|
# desired. DSpace treats the first and last name attributes differently because
|
||||||
|
# they (along with email address) are the three pieces of minimal information
|
||||||
|
# required to create a new user account. For both first and last name supply
|
||||||
|
# direct mappings to the Shibboleth headers. In additional to the first and
|
||||||
|
# last name DSpace supports other metadata fields such as phone, or really
|
||||||
|
# anything you want to store on an eperson object. Beyond the phone field,
|
||||||
|
# which is accessible in the user's profile screen, none of these additional
|
||||||
|
# metadata fields will be used by DSpace out-of-the box. However if you
|
||||||
|
# develop any local modification you may access these attributes from the
|
||||||
|
# EPerson object. The Vireo ETD workflow system utilizes this to aid
|
||||||
|
# students when submitting an ETD.
|
||||||
|
|
||||||
# The following mappings specify role mapping between IdP and Dspace.
|
# Metadata Headers
|
||||||
# the left side of the entry is IdP's role (prefixed with
|
# Shibboleth-based headers for the first and last name attirbutes
|
||||||
# "role.") which will be mapped to
|
firstname-header = SHIB-GIVENNAME
|
||||||
# the right entry from DSpace. DSpace's group as indicated on the
|
lastname-header = SHIB-SURNAME
|
||||||
# right entry has to EXIST in DSpace, otherwise user will be identified
|
|
||||||
# as 'anonymous'. Multiple values on the right entry should be separated
|
# Additional user attributes mapping, multiple attributes may be stored
|
||||||
# by comma. The values are CASE-Sensitive. Heuristic one-to-one mapping
|
# for each user. The left side is the Shibboleth-based metadata Header
|
||||||
# will be done when the IdP groups entry are not listed below (i.e.
|
# and the right side is the eperson metadata field to map the attribute to.
|
||||||
# if "X" group in IdP is not specified here, then it will be mapped
|
#eperson.metadata = \
|
||||||
# to "X" group in DSpace if it exists, otherwise it will be mapped
|
# SHIB-telephone => phone, \
|
||||||
# to simply 'anonymous')
|
# SHIB-cn => cn
|
||||||
|
|
||||||
|
# If the eperson metadata field is not found, should it be automatically created?
|
||||||
|
eperson.metadata.autocreate = true;
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
## Role-based Groups:
|
||||||
|
##
|
||||||
|
# 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.
|
||||||
#
|
#
|
||||||
# Given sufficient demand, future release could support regex for the mapping
|
# Depending upon the shibboleth attributed use in the role-header it may be
|
||||||
# special characters need to be escaped by \
|
# scoped. Scoped is shibboleth terminology for identifying where an attribute
|
||||||
role.Senior\ Researcher = Researcher, Staff
|
# originated from. For example a students affiliation may be encoded as
|
||||||
role.Librarian = Administrator
|
# "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
|
||||||
|
# "role.<role-name>" which is a comma separated list of
|
||||||
|
# DSpace groups.
|
||||||
|
|
||||||
|
# The shibboleth header to do role-based mappings
|
||||||
|
role-header = SHIB-SCOPED-AFFILIATION
|
||||||
|
|
||||||
|
# Weather to ignore the attribute's scope or value.
|
||||||
|
role-header.ignore-scope = true
|
||||||
|
#role-header.ignore-value = false
|
||||||
|
|
||||||
|
# Default mappings of roles values to a comma separated list of DSpace group
|
||||||
|
# names (Case Sensitive).
|
||||||
|
#role.faculty = Faculty, Member
|
||||||
|
#role.staff = Staff, Member
|
||||||
|
#role.student = Students, Member
|
Reference in New Issue
Block a user