[LON-CAPA-cvs] cvs: loncom / lond /auth lonauth.pm /enrollment localenroll.pm /html/adm/help/tex Domain_Configuration_LangTZAuth.tex /interface domainprefs.pm /lonnet/perl lonnet.pm
raeburn
raeburn at source.lon-capa.org
Sat Feb 26 20:43:15 EST 2022
raeburn Sun Feb 27 01:43:15 2022 EDT
Modified files:
/loncom lond
/loncom/auth lonauth.pm
/loncom/interface domainprefs.pm
/loncom/enrollment localenroll.pm
/loncom/lonnet/perl lonnet.pm
/loncom/html/adm/help/tex Domain_Configuration_LangTZAuth.tex
Log:
- Domain configuration to allow authentication of an alternate username, if
username entered differs from real username in a predictable way,
e.g., username entered in log-in page was email address (userid at example.tld)
instead of just userid.
-------------- next part --------------
Index: loncom/lond
diff -u loncom/lond:1.574 loncom/lond:1.575
--- loncom/lond:1.574 Fri Feb 25 09:38:47 2022
+++ loncom/lond Sun Feb 27 01:43:13 2022
@@ -2,7 +2,7 @@
# The LearningOnline Network
# lond "LON Daemon" Server (port "LOND" 5663)
#
-# $Id: lond,v 1.574 2022/02/25 09:38:47 raeburn Exp $
+# $Id: lond,v 1.575 2022/02/27 01:43:13 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -65,7 +65,7 @@
my $status='';
my $lastlog='';
-my $VERSION='$Revision: 1.574 $'; #' stupid emacs
+my $VERSION='$Revision: 1.575 $'; #' stupid emacs
my $remoteVERSION;
my $currenthostid="default";
my $currentdomainid;
@@ -259,6 +259,7 @@
instidrules => {remote => 1, domroles => 1,},
instrulecheck => {remote => 1, enroll => 1, reqcrs => 1, domroles => 1},
instselfcreatecheck => {institutiononly => 1},
+ instunamemapcheck => {remote => 1,},
instuserrules => {remote => 1, enroll => 1, reqcrs => 1, domroles => 1},
keys => {remote => 1,},
load => {anywhere => 1},
@@ -312,6 +313,7 @@
tmpget => {institutiononly => 1},
tmpput => {remote => 1, othcoau => 1},
tokenauthuserfile => {anywhere => 1},
+ unamemaprules => {remote => 1,},
unsub => {content => 1,},
update => {shared => 1},
updatebalcookie => {institutiononly => 1},
@@ -2655,6 +2657,36 @@
return;
}
+sub inst_unamemap_check {
+ my ($cmd, $tail, $client) = @_;
+ my $userinput = "$cmd:$tail";
+ my %rulecheck;
+ my $outcome;
+ my ($udom,$uname, at rules) = split(/:/,$tail);
+ $udom = &unescape($udom);
+ $uname = &unescape($uname);
+ @rules = map {&unescape($_);} (@rules);
+ eval {
+ local($SIG{__DIE__})='DEFAULT';
+ $outcome = &localenroll::unamemap_check($udom,$uname,\@rules,\%rulecheck);
+ };
+ if (!$@) {
+ if ($outcome eq 'ok') {
+ my $result='';
+ foreach my $key (keys(%rulecheck)) {
+ $result.=&escape($key).'='.&Apache::lonnet::freeze_escape($rulecheck{$key}).'&';
+ }
+ &Reply($client,\$result,$userinput);
+ } else {
+ &Reply($client,"error\n", $userinput);
+ }
+ } else {
+ &Failure($client,"unknown_cmd\n",$userinput);
+ }
+}
+®ister_handler("instunamemapcheck",\&inst_unamemap_check,0,1,0);
+
+
#
# Determines if this is the home server for a user. The home server
# for a user will have his/her lon-capa passwd file. Therefore all we need
@@ -6806,6 +6838,39 @@
}
®ister_handler("instemailrules",\&get_institutional_selfcreate_rules,0,1,0);
+sub get_unamemap_rules {
+ my ($cmd, $tail, $client) = @_;
+ my $userinput = "$cmd:$tail";
+ my $dom = &unescape($tail);
+ my (%rules_hash, at rules_order);
+ my $outcome;
+ eval {
+ local($SIG{__DIE__})='DEFAULT';
+ $outcome = &localenroll::unamemap_rules($dom,\%rules_hash,\@rules_order);
+ };
+ if (!$@) {
+ if ($outcome eq 'ok') {
+ my $result;
+ foreach my $key (keys(%rules_hash)) {
+ $result .= &escape($key).'='.&Apache::lonnet::freeze_escape($rules_hash{$key}).'&';
+ }
+ $result =~ s/\&$//;
+ $result .= ':';
+ if (@rules_order > 0) {
+ foreach my $item (@rules_order) {
+ $result .= &escape($item).'&';
+ }
+ }
+ $result =~ s/\&$//;
+ &Reply($client,\$result,$userinput);
+ } else {
+ &Reply($client,"error\n", $userinput);
+ }
+ } else {
+ &Failure($client,"unknown_cmd\n",$userinput);
+ }
+}
+®ister_handler("unamemaprules",\&get_unamemap_rules,0,1,0);
sub institutional_username_check {
my ($cmd, $tail, $client) = @_;
@@ -8390,7 +8455,7 @@
#
# Don't attempt authentication for username and password supplied
# for user without an account if uername contains @ to avoid
- # call to &Authen::Krb5::parse_name() which will result in con_lost
+ # call to &Authen::Krb5::parse_name() which will result in con_lost
#
unless ($user =~ /\@/) {
$howpwd = $domdefaults{'auth_def'};
Index: loncom/auth/lonauth.pm
diff -u loncom/auth/lonauth.pm:1.171 loncom/auth/lonauth.pm:1.172
--- loncom/auth/lonauth.pm:1.171 Wed Nov 24 20:15:15 2021
+++ loncom/auth/lonauth.pm Sun Feb 27 01:43:13 2022
@@ -1,7 +1,7 @@
# The LearningOnline Network
# User Authentication Module
#
-# $Id: lonauth.pm,v 1.171 2021/11/24 20:15:15 raeburn Exp $
+# $Id: lonauth.pm,v 1.172 2022/02/27 01:43:13 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -583,9 +583,33 @@
# --------------------------------------------------------------------- Failed?
if ($authhost eq 'no_host') {
- &failed($r,'Username and/or password could not be authenticated.',
- \%form,$authhost);
- return OK;
+ my $pwdverify;
+ if (&Apache::lonnet::homeserver($form{'uname'},$form{'udom'}) eq 'no_host') {
+ my %possunames = &alternate_unames_check($form{'uname'},$form{'udom'});
+ if (keys(%possunames) > 0) {
+ foreach my $rulematch (keys(%possunames)) {
+ my $possuname = $possunames{$rulematch};
+ if (($possuname ne '') && ($possuname =~ /^$match_username$/)) {
+ $authhost=Apache::lonnet::authenticate($possuname,$upass,
+ $form{'udom'},undef,
+ $clientcancheckhost);
+ if (($authhost eq 'no_host') || ($authhost eq 'no_account_on_host')) {
+ next;
+ } elsif (($authhost ne '') && (&Apache::lonnet::hostname($authhost) ne '')) {
+ $pwdverify = 1;
+ &Apache::lonnet::logthis("Authenticated user: $possuname was submitted as: $form{'uname'}");
+ $form{'uname'} = $possuname;
+ last;
+ }
+ }
+ }
+ }
+ }
+ unless ($pwdverify) {
+ &failed($r,'Username and/or password could not be authenticated.',
+ \%form,$authhost);
+ return OK;
+ }
} elsif ($authhost eq 'no_account_on_host') {
if ($defaultauth) {
my $domdesc = &Apache::lonnet::domain($form{'udom'},'description');
@@ -1086,6 +1110,20 @@
return;
}
+sub alternate_unames_check {
+ my ($uname,$udom) = @_;
+ my %possunames;
+ my %domdefs = &Apache::lonnet::get_domain_defaults($udom);
+ if (ref($domdefs{'unamemap_rule'}) eq 'ARRAY') {
+ if (@{$domdefs{'unamemap_rule'}} > 0) {
+ %possunames =
+ &Apache::lonnet::inst_rulecheck($udom,$uname,undef,
+ 'unamemap',$domdefs{'unamemap_rule'});
+ }
+ }
+ return %possunames;
+}
+
1;
__END__
Index: loncom/interface/domainprefs.pm
diff -u loncom/interface/domainprefs.pm:1.408 loncom/interface/domainprefs.pm:1.409
--- loncom/interface/domainprefs.pm:1.408 Fri Feb 18 13:39:22 2022
+++ loncom/interface/domainprefs.pm Sun Feb 27 01:43:14 2022
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Handler to set domain-wide configuration settings
#
-# $Id: domainprefs.pm,v 1.408 2022/02/18 13:39:22 raeburn Exp $
+# $Id: domainprefs.pm,v 1.409 2022/02/27 01:43:14 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -327,7 +327,9 @@
header => [{col1 => 'Setting',
col2 => 'Value'},
{col1 => 'Institutional user types',
- col2 => 'Name displayed'}],
+ col2 => 'Name displayed'},
+ {col1 => 'Mapping for missing usernames via standard log-in',
+ col2 => 'Rules in use'}],
print => \&print_defaults,
modify => \&modify_defaults,
},
@@ -983,7 +985,7 @@
if (($action eq 'autoupdate') || ($action eq 'usercreation') ||
($action eq 'selfcreation') || ($action eq 'selfenrollment') ||
($action eq 'usersessions') || ($action eq 'coursecategories') ||
- ($action eq 'trust') || ($action eq 'contacts') ||
+ ($action eq 'trust') || ($action eq 'contacts') || ($action eq 'defaults') ||
($action eq 'privacy') || ($action eq 'passwords') || ($action eq 'lti')) {
if ($action eq 'coursecategories') {
$output .= &print_coursecategories('middle',$dom,$item,$settings,\$rowtotal);
@@ -1071,8 +1073,8 @@
}
$rowtotal ++;
} elsif (($action eq 'usermodification') || ($action eq 'coursedefaults') ||
- ($action eq 'defaults') || ($action eq 'directorysrch') ||
- ($action eq 'helpsettings') || ($action eq 'wafproxy')) {
+ ($action eq 'directorysrch') || ($action eq 'helpsettings') ||
+ ($action eq 'wafproxy')) {
$output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);
} elsif ($action eq 'scantron') {
$output .= $item->{'print'}->($r,'bottom',$dom,$confname,$settings,\$rowtotal);
@@ -10467,7 +10469,7 @@
'username' => 'new usernames',
'id' => 'IDs',
);
- unless ($type eq 'email') {
+ unless (($type eq 'email') || ($type eq 'unamemap')) {
my $css_class = $rowcount%2?' class="LC_odd_row"':'';
$output = '<tr '.$css_class.'>'.
'<td><span class="LC_nobreak">'.
@@ -10522,9 +10524,9 @@
} elsif ($colsleft == 1) {
$output .= '<td class="LC_left_item"> </td>';
}
- $output .= '</tr></table>';
- unless ($type eq 'email') {
- $output .= '</td></tr>';
+ $output .= '</tr>';
+ unless (($type eq 'email') || ($type eq 'unamemap')) {
+ $output .= '</table></td></tr>';
}
return $output;
}
@@ -10667,7 +10669,7 @@
$datatable .= '</td></tr>';
$rownum ++;
}
- } else {
+ } elsif ($position eq 'middle') {
my %defaults;
if (ref($settings) eq 'HASH') {
if ((ref($settings->{'inststatusorder'}) eq 'ARRAY') && (ref($settings->{'inststatustypes'}) eq 'HASH')) {
@@ -10717,6 +10719,22 @@
$rownum ++;
}
}
+ } else {
+ my ($unamemaprules,$ruleorder) =
+ &Apache::lonnet::inst_userrules($dom,'unamemap');
+ $css_class = $rownum%2?' class="LC_odd_row"':'';
+ if ((ref($unamemaprules) eq 'HASH') && (ref($ruleorder) eq 'ARRAY')) {
+ my $numinrow = 2;
+ $datatable .= '<tr'.$css_class.'><td>'.&mt('Available conversions').'</td><td><table>'.
+ &user_formats_row('unamemap',$settings,$unamemaprules,
+ $ruleorder,$numinrow).
+ '</table></td></tr>';
+ }
+ if ($datatable eq '') {
+ $datatable .= '<tr'.$css_class.'><td colspan="2">'.
+ &mt('No rules set for domain in customized localenroll.pm').
+ '</td></tr>';
+ }
}
$$rowtotal += $rownum;
return $datatable;
@@ -19972,6 +19990,41 @@
$newvalues{$item} = $staticdefaults{$item};
}
}
+ my ($unamemaprules,$ruleorder);
+ my @possunamemaprules = &Apache::loncommon::get_env_multiple('form.unamemap_rule');
+ if (@possunamemaprules) {
+ ($unamemaprules,$ruleorder) =
+ &Apache::lonnet::inst_userrules($dom,'unamemap');
+ if ((ref($unamemaprules) eq 'HASH') && (ref($ruleorder) eq 'ARRAY')) {
+ if (@{$ruleorder} > 0) {
+ my %possrules;
+ map { $possrules{$_} = 1; } @possunamemaprules;
+ foreach my $rule (@{$ruleorder}) {
+ if ($possrules{$rule}) {
+ push(@{$newvalues{'unamemap_rule'}},$rule);
+ }
+ }
+ }
+ }
+ }
+ if (ref($domdefaults{'unamemap_rule'}) eq 'ARRAY') {
+ if (ref($newvalues{'unamemap_rule'}) eq 'ARRAY') {
+ my @rulediffs = &Apache::loncommon::compare_arrays($domdefaults{'unamemap_rule'},
+ $newvalues{'unamemap_rule'});
+ if (@rulediffs) {
+ $changes{'unamemap_rule'} = 1;
+ $domdefaults{'unamemap_rule'} = $newvalues{'unamemap_rule'};
+ }
+ } elsif (@{$domdefaults{'unamemap_rule'}} > 0) {
+ $changes{'unamemap_rule'} = 1;
+ delete($domdefaults{'unamemap_rule'});
+ }
+ } elsif (ref($newvalues{'unamemap_rule'}) eq 'ARRAY') {
+ if (@{$newvalues{'unamemap_rule'}} > 0) {
+ $changes{'unamemap_rule'} = 1;
+ $domdefaults{'unamemap_rule'} = $newvalues{'unamemap_rule'};
+ }
+ }
my %defaults_hash = (
defaults => \%newvalues,
);
@@ -20086,6 +20139,26 @@
$resulttext .= '<li>'.&mt('Institutional user status types deleted').'</li>';
}
}
+ } elsif ($item eq 'unamemap_rule') {
+ if (ref($newvalues{'unamemap_rule'}) eq 'ARRAY') {
+ my @rulenames;
+ if (ref($unamemaprules) eq 'HASH') {
+ foreach my $rule (@{$newvalues{'unamemap_rule'}}) {
+ if (ref($unamemaprules->{$rule}) eq 'HASH') {
+ push(@rulenames,$unamemaprules->{$rule}->{'name'});
+ }
+ }
+ }
+ if (@rulenames) {
+ $resulttext .= '<li>'.&mt('Mapping for missing usernames includes: [_1]',
+ '<ul><li>'.join('</li><li>', at rulenames).'</li></ul>').
+ '</li>';
+ } else {
+ $resulttext .= '<li>'.&mt('No mapping for missing usernames via standard log-in').'</li>';
+ }
+ } else {
+ $resulttext .= '<li>'.&mt('Mapping for missing usernames via standard log-in deleted').'</li>';
+ }
} else {
my $value = $env{'form.'.$item};
if ($value eq '') {
Index: loncom/enrollment/localenroll.pm
diff -u loncom/enrollment/localenroll.pm:1.63 loncom/enrollment/localenroll.pm:1.64
--- loncom/enrollment/localenroll.pm:1.63 Fri Jan 14 16:27:20 2022
+++ loncom/enrollment/localenroll.pm Sun Feb 27 01:43:14 2022
@@ -1,6 +1,6 @@
# functions to glue school database system into Lon-CAPA for
# automated enrollment
-# $Id: localenroll.pm,v 1.63 2022/01/14 16:27:20 raeburn Exp $
+# $Id: localenroll.pm,v 1.64 2022/02/27 01:43:14 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -1157,7 +1157,7 @@
=pod
-=item get_multusersinfo
+=item get_multusersinfo()
(a) $dom - domain
(b) $type - username or id
@@ -1250,8 +1250,8 @@
keys of top level hash are short names
(e.g., netid, noncredit)
for each key, value is a hash
- desc => long name for rule
- rule => description of rule
+ name => long name for rule
+ desc => description of rule
authtype => (krb5,krb4,int, or loc)
authentication type for rule
authparm => authentication parameter for rule
@@ -1285,8 +1285,8 @@
keys of top level hash are short names
(e.g., netid, noncredit)
for each key, value is a hash
- desc => long name for rule
- rule => description of rule
+ name => long name for rule
+ desc => description of rule
(c) $rulesorder - reference to array containing rule names
in order to be displayed
@@ -1312,8 +1312,8 @@
keys of top level hash are short names
(e.g., netid)
for each key, value is a hash
- desc => long name for rule
- rule => description of rule
+ name => long name for rule
+ desc => description of rule
(c) $rulesorder - reference to array containing rule names
in order to be displayed
@@ -1331,6 +1331,46 @@
=pod
+=item unamemap_rules()
+
+ Incoming data: three arguments
+ (a) $dom - domain
+ (b) $ruleshash - reference to hash containing rules
+ (a hash of a hash)
+ keys of top level hash are short names
+ (e.g., netid)
+ for each key, value is a hash
+ name => long name for rule
+ desc => description of rule
+
+ For example:
+
+ %{$ruleshash} = (
+ emailaddress => {
+ name => 'Email address to UserID',
+ desc => 'Extract userID from userID at example.tld',
+ },
+ );
+ would enable display of a checkbox for: 'Email address to UserID' in the
+ "Available conversions" item in the "Mapping for missing usernames via standard log-in"
+ panel available to a Domain Coordinator via:
+ Main Menu > Set domain configuration > Display ("Default authentication/language/timezone/portal/types" checked)
+
+ (c) $rulesorder - reference to array containing rule names
+ in order to be displayed
+
+ returns 'ok' if no processing error.
+
+=cut
+
+sub unamemap_rules {
+ my ($dom,$ruleshash,$rulesorder) = @_;
+ my $outcome;
+ return $outcome;
+}
+
+=pod
+
=item username_check()
Incoming data: four arguments
@@ -1338,7 +1378,7 @@
(b) $uname - username to compare against rules (scalar)
(c) $to_check (reference to array of rule names to check)
(d) $resultshash (reference to hash of results)
- hash of results for rule checked
+ hash of results for rules checked
- keys are rule names
- values are: 1 or 0 (for matched or unmatched)
@@ -1362,7 +1402,7 @@
(b) $id - ID to compare against rules (scalar)
(c) $to_check (reference to array of rule names to check)
(d) $resultshash (reference to hash of results)
- hash of results for rule checked
+ hash of results for rules checked
- keys are rule names
- values are: 1 or 0 (for matched or unmatched)
@@ -1386,7 +1426,7 @@
(b) $selfcreatename - e-mail proposed as username (compare against rules - scalar)
(c) $to_check (reference to array of rule names to check)
(d) $resultshash (reference to hash of results)
- hash of results for rule checked
+ hash of results for rules checked
- keys are rule names
- values are: 1 or 0 (for matched or unmatched)
@@ -1403,6 +1443,44 @@
=pod
+=item unamemap_check()
+
+ Incoming data: four arguments
+ (a) $dom - domain (scalar)
+ (b) $uname - username entered on log-in page (compare against rules - scalar)
+ (c) $to_check (reference to array of rule names to check)
+ (d) $resultshash (reference to hash of results)
+ hash of results for rules checked
+ - keys are rule names
+ - values are derived username from substitution operation
+ applied to $uname.
+
+ For example, in the msu domain the rule "msuemail" will replace an MSU
+ email address submitted as a username, with the part before the @msu.edu,
+ (known as the MSUNetID), which is what is used in LON-CAPA as a username.
+
+ if ($dom eq 'msu') {
+ foreach my $item (@{$to_check}) {
+ if ($item eq 'msuemail') {
+ if ($uname =~ /^(\w{2,8})\@msu\.edu$/) {
+ $resultshash->{$item} = $1;
+ }
+ }
+ }
+ }
+
+ returns 'ok' if no processing error.
+
+=cut
+
+sub unamemap_check {
+ my ($dom,$uname,$to_check,$resultshash) = @_;
+ my $outcome;
+ return $outcome;
+}
+
+=pod
+
=item AUTOLOAD()
Incoming data: none
Index: loncom/lonnet/perl/lonnet.pm
diff -u loncom/lonnet/perl/lonnet.pm:1.1483 loncom/lonnet/perl/lonnet.pm:1.1484
--- loncom/lonnet/perl/lonnet.pm:1.1483 Thu Feb 17 22:35:52 2022
+++ loncom/lonnet/perl/lonnet.pm Sun Feb 27 01:43:14 2022
@@ -1,7 +1,7 @@
# The LearningOnline Network
# TCP networking package
#
-# $Id: lonnet.pm,v 1.1483 2022/02/17 22:35:52 raeburn Exp $
+# $Id: lonnet.pm,v 1.1484 2022/02/27 01:43:14 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -1323,7 +1323,7 @@
sub queryauthenticate {
my ($uname,$udom)=@_;
my $uhome=&homeserver($uname,$udom);
- if (!$uhome) {
+ if ((!$uhome) || ($uhome eq 'no_host')) {
&logthis("User $uname at $udom is unknown when looking for authentication mechanism");
return 'no_host';
}
@@ -1372,7 +1372,7 @@
}
if ($answer eq 'non_authorized') {
&logthis("User $uname at $udom rejected by $uhome");
- return 'no_host';
+ return 'no_host';
}
&logthis("User $uname at $udom threw error $answer when checking authentication mechanism");
return 'no_host';
@@ -2593,6 +2593,10 @@
$response=&unescape(&reply('instselfcreatecheck:'.
&escape($udom).':'.&escape($uname).
':'.$rulestr,$homeserver));
+ } elsif ($item eq 'unamemap') {
+ $response=&unescape(&reply('instunamemapcheck:'.
+ &escape($udom).':'.&escape($uname).
+ ':'.$rulestr,$homeserver));
}
if ($response ne 'refused') {
my @pairs=split(/\&/,$response);
@@ -2622,6 +2626,9 @@
} elsif ($check eq 'email') {
$response=&reply('instemailrules:'.&escape($udom),
$homeserver);
+ } elsif ($check eq 'unamemap') {
+ $response=&reply('unamemaprules:'.&escape($udom),
+ $homeserver);
} else {
$response=&reply('instuserrules:'.&escape($udom),
$homeserver);
@@ -2680,6 +2687,7 @@
$domdefaults{'intauth_cost'} = $domconfig{'defaults'}{'intauth_cost'};
$domdefaults{'intauth_switch'} = $domconfig{'defaults'}{'intauth_switch'};
$domdefaults{'intauth_check'} = $domconfig{'defaults'}{'intauth_check'};
+ $domdefaults{'unamemap_rule'} = $domconfig{'defaults'}{'unamemap_rule'};
} else {
$domdefaults{'lang_def'} = &domain($domain,'lang_def');
$domdefaults{'auth_def'} = &domain($domain,'auth_def');
Index: loncom/html/adm/help/tex/Domain_Configuration_LangTZAuth.tex
diff -u loncom/html/adm/help/tex/Domain_Configuration_LangTZAuth.tex:1.12 loncom/html/adm/help/tex/Domain_Configuration_LangTZAuth.tex:1.13
--- loncom/html/adm/help/tex/Domain_Configuration_LangTZAuth.tex:1.12 Wed Jan 8 19:03:55 2020
+++ loncom/html/adm/help/tex/Domain_Configuration_LangTZAuth.tex Sun Feb 27 01:43:14 2022
@@ -51,3 +51,35 @@
\item \textit{Assignment to ``email-based'' usernames} Whether status type can also be assigned to a non-institutional user with an e-mail address as username
\end{itemize}
+\textbf{Mapping for missing usernames via standard log-in} can be enabled for the domain via the same screen.
+
+For a user who logs-in to LON-CAPA via the standard log-in screen, customization is available to support credentials
+checking with an alternate username (but same password) if the username, as originally entered by the user, should
+be altered in a predictable way, to make it consistent with the format expected for usernames in the domain.
+
+An example is where an email address is supplied as the username by the user, but the part of the email address
+which precedes the @ in the email address is what is actually used in LON-CAPA for the user's username.
+
+A complication is the fact that a domain may support both types of username, e.g., userID, and userID at example.tld,
+as legitimate usernames for different types of user. For example the usernames for official users may look like: userID,
+but privileged users may also create user accounts for guest users (including ``fictitous'' usernames for themselves, to
+use to test course behavior as a student) which look like: userID at example.tld.
+
+To accommodate that possibility, LON-CAPA will first attempt to authenticate the username and password, but if a user
+does not exist for the supplied username in the domain, can then see if a ``real'' username can be extracted from
+the one supplied, and make a second attempt to authenticate using the derived username with the password. Accordingly,
+authentication would fail for: userID at example.tld if that user did not exist, but might succeed for userID if that user
+did exist, and the password supplied matched what was expected.
+
+To enable this functionality requires customizing two routines in /home/httpd/lib/perl/localenroll.pm:
+&unamemap_rules() and &unamemap_check(). There are stubs for both of them (with documentation) in the
+uncustomized template file: /home/httpd/lib/perl/localenroll-std.pm. Restart of loncontrol is required
+after making changes to localenroll.pm.
+
+Once &unamemap_rules() contains at least one rule, then the ``Default authentication/language/timezone/portal/types''
+domain configuration will include a checkbox for at least one rule in ``Available conversions'' listed in the
+``Mapping for missing usernames via standard log-in'' section. Checking the checkbox and pushing ``Save Changes''
+will make the corresponding conversion for that rule, as coded in &unamemap_check(), available to create
+a derived username for a second authentication attempt, if the original username did not exist, but matched
+the required format for the conversion.
+
More information about the LON-CAPA-cvs
mailing list