Annotation of loncom/html/adm/help/tex/Institutional_Integration_Identity_Management.tex, revision 1.4

1.2       raeburn     1: \label{Institutional_Integration_Identity_Management}
1.1       raeburn     2: Two subroutines exist in localenroll.pm to provide a connection between
                      3: institutional directory data (e.g., user information from LDAP) and
                      4: LON-CAPA. The first is \emph{get\_userinfo()} which can operate in
                      5: two modes.: (a) it can be used to provide first name, last name, e-mail
                      6: address, student/employee ID etc., for a specified username, e.g.,
                      7: for a new user being created in LON-CAPA, and (b) it can be used to
                      8: retrieve user information for multiple users from an institutional
                      9: directory searches when (for example) a course coordinator is adding
                     10: a new user directly to a course. At MSU the routine which actually
                     11: queries institutional data sources is itself called by \emph{get\_userinfo()}.
                     12: This was done so that the same underlying routine can also be used
                     13: by the second of the two subroutines: \emph{allusers\_info()} which
                     14: is called by Autoupdate.pl (a script which can be run periodically
                     15: to reconcile user information in LON-CAPA with institutional directory
                     16: data for all users).
                     17: 
                     18: 
                     19: 
                     20: \textbf{\large get\_userinfo}{\large \par}
                     21: 
                     22: Four required arguments and additional optional arguments
                     23: 
                     24: Two modes of operation:
                     25: 
                     26: \begin{enumerate}
                     27: \item Retrieves institutional data for a single user either by username,
                     28: if \$uname is included as second argument, 
                     29: 
                     30: 
                     31: or by ID if \$id is included as a third argument. Either second or
                     32: third arguments must be provided; seventh, eighth and ninth args will
                     33: be undefined.
                     34: 
                     35: \item Retrieves institutional user data from search of an institutional
                     36: directory based on a search. seventh and eighth args are required;
                     37: ninth is optional. second and third will be undefined.
                     38: \end{enumerate}
                     39: Arguments:
                     40: 
                     41: \begin{enumerate}
                     42: \item \$dom - domain
                     43: \item \$uname - username of user
                     44: \item \$id - student/faculty ID of user
                     45: \item \$instusers - reference to hash which will contain info for user as
                     46: key = value; keys will be one or all of: lastname, firstname, middlename,
                     47: generation, id, inststatus - institutional status (e.g., faculty,staff,student). 
                     48: 
                     49: 
                     50: Values are all scalars except inststatus, which is an array.
                     51: 
                     52: \item \$instids - reference to hash which will contain ID numbers - keys
                     53: will be unique IDs (student or faculty/staff ID) 
                     54: 
                     55: 
                     56: values will be either: scalar (username) or an array if a single ID
                     57: matches multiple usernames.
                     58: 
                     59: \item \$types - optional reference to array which contains institutional
                     60: types to check.
                     61: \item \$srchby - optional if \$uname or \$id defined, otherwise required.
                     62: 
                     63: 
                     64: Allowed values include: 1. lastfirst, 2. last, 3. uname corresponding
                     65: to searches by 1. lastname,firstname; 2. lastname; 3. username
                     66: 
                     67: \item \$srchterm - optional if \$uname or \$id defined, otherwise required
                     68: - String to search for.
                     69: \item \$srchtype - optional. Allowed values: contains, begins (defaults
                     70: to exact match otherwise).
                     71: \end{enumerate}
                     72: Returns 'ok' if no error occurred. Side effects - populates the \$instusers
                     73: and \$instids refs to hashes with information for specified username,
                     74: or specified id, if fifth argument provided, from all available, or
                     75: specified (e.g., faculty only) institutional datafeeds, if sixth argument
                     76: provided.
                     77: 
                     78: At MSU six separate MS-SQL database tables are queried, with each
1.3       raeburn    79: table corresponding to a specific institutional type. A routine is
1.1       raeburn    80: called to connect to the database. and the actual queries are handled
                     81: by a separate routine - \emph{query\_user\_tables()}.
                     82: 
                     83: \begin{quotation}
                     84: \texttt{sub get\_userinfo \{}
                     85: \begin{quotation}
                     86: \texttt{my (\$dom,\$uname,\$id,\$instusers,\$instids,\$types,}
                     87: \begin{quotation}
                     88: \texttt{\$srchby,\$srchterm,\$srchtype) = @\_;}
                     89: \end{quotation}
                     90: \texttt{my \$outcome;}
                     91: \begin{quotation}
                     92: \texttt{my @srchtables;}
                     93: \end{quotation}
                     94: \texttt{my \%tables = (}
                     95: \begin{quotation}
                     96: \texttt{Faculty => 'FACULTY\_VU',}
                     97: 
                     98: \texttt{Staff => 'STAFF\_VU',}
                     99: 
                    100: \texttt{Student => 'STUDENT',}
                    101: 
                    102: \texttt{Assistant => 'ASSISTANT',}
                    103: 
                    104: \texttt{StaffAff => 'AFFILIATE',}
                    105: 
                    106: \texttt{StuAff => 'STUDENT\_AFFILIATE'}
                    107: \end{quotation}
                    108: \texttt{);}
                    109: 
                    110: \texttt{my (\$dbh,\$dbflag) = \&connect\_DB('HR');}
                    111: 
                    112: \texttt{foreach my \$type (@\{\$types\}) \{}
                    113: \begin{quotation}
                    114: \texttt{if (exists(\$tables\{\$type\})) \{}
                    115: \begin{quotation}
                    116: \texttt{push(@srchtables,\$tables\{\$type\});}
                    117: \end{quotation}
                    118: \texttt{\}}
                    119: \end{quotation}
                    120: \texttt{\}}
                    121: 
                    122: \texttt{if (@srchtables == 0) \{}
                    123: \begin{quotation}
                    124: \texttt{foreach my \$type (keys(\%tables)) \{}
                    125: \begin{quotation}
                    126: \texttt{push(@srchtables,\$tables\{\$type\});}
                    127: \end{quotation}
                    128: \texttt{\}}
                    129: \end{quotation}
                    130: \texttt{\}}
                    131: 
                    132: \texttt{if (\$srchby eq '' \&\& \$srchterm eq '') \{}
                    133: \begin{quotation}
                    134: \texttt{if (\$uname ne '') \{}
                    135: \begin{quotation}
                    136: \texttt{\$srchby = 'uname';}
                    137: 
                    138: \texttt{\$srchterm = \$uname;}
                    139: \end{quotation}
                    140: \texttt{\} elsif (\$id ne '') \{}
                    141: \begin{quotation}
                    142: \texttt{\$srchby = 'id';}
                    143: 
                    144: \texttt{\$srchterm = \$id;}
                    145: \end{quotation}
                    146: \texttt{\}}
                    147: \end{quotation}
                    148: \texttt{\}}
                    149: 
                    150: \texttt{if (\$srchterm ne '') \{}
                    151: \begin{quotation}
                    152: \texttt{\$outcome = \&query\_user\_tables(\$dbflag,\$dbh,\textbackslash{}@srchtables,\$instusers,\$instids,}
                    153: \begin{quotation}
                    154: \texttt{\$srchby,\$srchterm,\$srchtype,\$types);}
                    155: \end{quotation}
                    156: \end{quotation}
                    157: \texttt{\}}
                    158: 
                    159: \texttt{if (\$dbflag) \{}
                    160: \begin{quotation}
                    161: \texttt{\&disconnect\_DB(\$dbh);}
                    162: \end{quotation}
                    163: \texttt{\}}
                    164: 
                    165: \texttt{return \$outcome;}
                    166: \end{quotation}
                    167: \texttt{\}}
                    168: 
                    169: Although query\_user\_tables() is not a subroutine included as a stub
                    170: in the standard localenroll.pm, it is included below to show how the
                    171: database queries are implemented at MSU.
                    172: 
                    173: \texttt{sub query\_user\_tables \{}
                    174: \begin{quotation}
                    175: \texttt{my (\$dbflag,\$dbh,\$srchtables,\$instusers,\$instids,\$srchby,\$srchterm,\$srchtype,\$types)
                    176: = @\_;}
                    177: 
                    178: \texttt{my (\$outcome,\$condition,\%multipids,\$ldapfilter);}
                    179: 
                    180: \texttt{if (\$srchby eq 'uname') \{}
                    181: \begin{quotation}
1.4     ! raeburn   182: \texttt{if (\$srchterm =\~{} /\^{}\textbackslash{}w\{2,8\}\$/)
1.1       raeburn   183: \{}
                    184: \begin{quotation}
                    185: \texttt{if (\$srchtype eq 'contains') \{}
                    186: 
1.4     ! raeburn   187: \texttt{~~\$condition = \char`\"{}WHERE MSUNetID LIKE '\%\$srchterm\%'\char`\"{};}
        !           188: 
        !           189: \texttt{~~\$ldapfilter = '(uid={*}'.\$srchterm.'{*})';}
        !           190: 
1.1       raeburn   191: \texttt{\} elsif (\$srchtype eq 'begins') \{}
                    192: 
1.4     ! raeburn   193: \texttt{~~\$condition = \char`\"{}WHERE MSUNetID LIKE '\$srchterm\%'\char`\"{};}
        !           194: 
        !           195: \texttt{~~\$ldapfilter = '(uid='.\$srchterm.'{*})';}
        !           196: 
1.1       raeburn   197: \texttt{\} else \{}
                    198: 
1.4     ! raeburn   199: \texttt{~~\$condition = \char`\"{}WHERE MSUNetID = '\$srchterm'\char`\"{};}
        !           200: 
        !           201: \texttt{~~\$ldapfilter = '(uid='.\$srchterm.')';}
        !           202: 
1.1       raeburn   203: \texttt{\}}
                    204: \end{quotation}
                    205: \texttt{\}}
                    206: \end{quotation}
                    207: \texttt{\} elsif (\$srchby eq 'lastname') \{}
                    208: \begin{quotation}
                    209: \texttt{if (\$srchterm =\~{} /{[}A-Za-z\textbackslash{}-\textbackslash{}.'\textbackslash{}s]+/)
                    210: \{}
                    211: \begin{quotation}
                    212: \texttt{if (\$srchtype eq 'contains') \{}
                    213: 
1.4     ! raeburn   214: \texttt{~~if (\$dbflag) \{}
        !           215: 
        !           216: \texttt{~~~~my \$quoted\_last = \$dbh->quote('\%'.\$srchterm.'\%');}
        !           217: 
        !           218: \texttt{~~~~\$condition = \char`\"{}WHERE LastName LIKE \$quoted\_last\char`\"{};}
        !           219: 
        !           220: \texttt{~~\}}
        !           221: 
        !           222: \texttt{~~\$ldapfilter = '(sn={*}'.\$srchterm.'{*})';}
1.1       raeburn   223: 
                    224: \texttt{\} elsif (\$srchtype eq 'begins') \{}
                    225: 
1.4     ! raeburn   226: \texttt{~~if (\$dbflag) \{}
        !           227: 
        !           228: \texttt{~~~~my \$quoted\_last = \$dbh->quote(\$srchterm.'\%');}
        !           229: 
        !           230: \texttt{~~~~\$condition = \char`\"{}WHERE LastName LIKE \$quoted\_last\char`\"{};}
        !           231: 
        !           232: \texttt{~~\}}
        !           233: 
        !           234: \texttt{~~\$ldapfilter = '(sn='.\$srchterm.'{*})';}
1.1       raeburn   235: 
                    236: \texttt{\} else \{}
                    237: 
1.4     ! raeburn   238: \texttt{~~if (\$dbflag) \{}
        !           239: 
        !           240: \texttt{~~~my \$quoted\_last = \$dbh->quote(\$srchterm);}
        !           241: 
        !           242: \texttt{~~~~\$condition = \char`\"{}WHERE LastName = \$quoted\_last\char`\"{};}
        !           243: 
        !           244: \texttt{~~\}}
        !           245: 
        !           246: \texttt{~~\$ldapfilter = '(sn='.\$srchterm.')';}
1.1       raeburn   247: 
                    248: \texttt{\}}
                    249: \end{quotation}
                    250: \texttt{\}}
                    251: \end{quotation}
                    252: \texttt{\} elsif (\$srchby eq 'lastfirst') \{}
                    253: \begin{quotation}
                    254: \texttt{my (\$srchlast,\$srchfirst) = split(/,/,\$srchterm);}
                    255: 
                    256: \texttt{\$srchlast =\~{} s/\textbackslash{}s+\$//;}
                    257: 
1.4     ! raeburn   258: \texttt{\$srchfirst =\~{} s/\^{}\textbackslash{}s+//;}
1.1       raeburn   259: 
                    260: \texttt{if ((\$srchlast =\~{} /{[}A-Za-z\textbackslash{}-\textbackslash{}.'\textbackslash{}s]+/)
                    261: \&\& (\$srchfirst =\~{} /{[}A-Za-z\textbackslash{}-\textbackslash{}.'\textbackslash{}s]+/))
                    262: \{}
                    263: \begin{quotation}
                    264: \texttt{my (\$quoted\_first,\$quoted\_last);}
                    265: 
                    266: \texttt{if (\$srchtype eq 'contains') \{}
                    267: 
1.4     ! raeburn   268: \texttt{~~if (\$dbflag) \{}
        !           269: 
        !           270: \texttt{~~~~\$quoted\_last = \$dbh->quote('\%'.\$srchlast.'\%');}
        !           271: 
        !           272: \texttt{~~~~\$quoted\_first = \$dbh->quote('\%'.\$srchfirst.'\%');}
1.1       raeburn   273: 
1.4     ! raeburn   274: \texttt{~~~~\$condition = \char`\"{}WHERE ( LastName LIKE \$quoted\_last
1.1       raeburn   275: AND FirstName LIKE \$quoted\_first )\char`\"{};}
                    276: 
1.4     ! raeburn   277: \texttt{~~\}}
        !           278: 
        !           279: \texttt{~~\$ldapfilter = '(\&(sn='.\$srchlast.'{*})(givenName='.\$srchfirst.'{*}))';}
        !           280: 
1.1       raeburn   281: \texttt{\} else \{}
                    282: \begin{quotation}
1.4     ! raeburn   283: \texttt{foreach my \$table (@\{\$srchtables\}) \{}
1.1       raeburn   284: \begin{quotation}
1.4     ! raeburn   285: \texttt{next if (\$srchby \&\& \$condition eq '');}
        !           286: 
        !           287: \texttt{my \$statement = \char`\"{}SELECT MSUNetID,Pid,FirstName,LastName,Person\_Type
        !           288: FROM \$table \$condition\char`\"{};}
        !           289: 
        !           290: \texttt{my \$sth = \$dbh->prepare(\char`\"{}\$statement\char`\"{});}
        !           291: 
        !           292: \texttt{\$sth->execute();}
        !           293: 
        !           294: \texttt{while ( my(\$uname,\$pid,\$first,\$last,\$type) = \$sth->fetchrow\_array
        !           295: ) \{}
1.1       raeburn   296: 
1.4     ! raeburn   297: \texttt{~~\$pid=lc(\$pid);}
1.1       raeburn   298: 
1.4     ! raeburn   299: \texttt{~~if (ref(\$instusers->\{\$uname\}) eq 'HASH') \{}
        !           300: 
        !           301: \texttt{~~~~if (ref(\$instusers->\{\$uname\}\{'instst}
        !           302: \end{quotation}
        !           303: \end{quotation}
        !           304: \texttt{~~if (\$dbflag) \{}
        !           305: 
        !           306: \texttt{~~~~\$quoted\_last = \$dbh->quote(\$srchterm);}
        !           307: 
        !           308: \texttt{~~~~\$quoted\_first = \$dbh->quote(\$srchterm);}
        !           309: 
        !           310: \texttt{~~~~\$condition = \char`\"{}WHERE ( LastName = \$quoted\_last
1.1       raeburn   311: AND FirstName = \$quoted\_first )\char`\"{};}
                    312: 
1.4     ! raeburn   313: \texttt{~~\}}
        !           314: 
        !           315: \texttt{~~\$ldapfilter = '(\&(sn='.\$srchlast.')(givenName='.\$srchfirst.'))';}
        !           316: 
1.1       raeburn   317: \texttt{\}}
                    318: \end{quotation}
                    319: \texttt{\}}
                    320: \end{quotation}
                    321: \texttt{\} elsif (\$srchby eq 'id') \{}
                    322: \begin{quotation}
                    323: \texttt{if (\$dbflag) \{}
1.4     ! raeburn   324: 
        !           325: \texttt{~~if (\$srchterm =\~{} /\^{}{[}AZ]\textbackslash{}d\{8\}\$/)
1.1       raeburn   326: \{}
                    327: \begin{quotation}
1.4     ! raeburn   328: \texttt{~~\$condition = \char`\"{}WHERE Pid = '\$srchterm'\char`\"{};}
1.1       raeburn   329: \end{quotation}
1.4     ! raeburn   330: \texttt{~~\}}
        !           331: 
1.1       raeburn   332: \texttt{\}}
                    333: \end{quotation}
                    334: \texttt{\}}
                    335: 
                    336: \texttt{if (\$dbflag) \{}
                    337: \begin{quotation}
                    338: \texttt{foreach my \$table (@\{\$srchtables\}) \{}
                    339: \begin{quotation}
                    340: \texttt{next if (\$srchby \&\& \$condition eq '');}
                    341: 
                    342: \texttt{my \$statement = \char`\"{}SELECT MSUNetID,Pid,FirstName,LastName,Person\_Type
                    343: FROM \$table \$condition\char`\"{};}
                    344: 
                    345: \texttt{my \$sth = \$dbh->prepare(\char`\"{}\$statement\char`\"{});}
                    346: 
                    347: \texttt{\$sth->execute();}
                    348: 
                    349: \texttt{while ( my(\$uname,\$pid,\$first,\$last,\$type) = \$sth->fetchrow\_array
                    350: ) \{}
                    351: 
1.4     ! raeburn   352: \texttt{~~\$pid=lc(\$pid);}
        !           353: 
        !           354: \texttt{~~if (ref(\$instusers->\{\$uname\}) eq 'HASH') \{}
        !           355: 
        !           356: \texttt{~~~~if (ref(\$instusers->\{\$uname\}\{'inststatus'\})
        !           357: eq 'ARRAY') \{}
        !           358: 
        !           359: \texttt{~~~~~~if (!grep(/\^{}\$type\$/,@\{\$instusers->\{\$uname\}\{'inststatus'\}\}))
1.1       raeburn   360: \{}
1.4     ! raeburn   361: 
        !           362: \texttt{~~~~~~~~push(@\{\$instusers->\{\$uname\}\{'inststatus'\}\},\$type);}
        !           363: 
        !           364: \texttt{~~~~~~\}}
        !           365: 
        !           366: \texttt{~~~~\}}
        !           367: 
        !           368: \texttt{~~~~if (\$pid ne \$instusers->\{\$uname\}\{'id'\}) \{}
        !           369: 
        !           370: \texttt{~~~~~~if (\$instusers->\{\$uname\}\{'id'\} =\~{}
        !           371: /\^{}A\textbackslash{}d\{8\}\$/) \{}
        !           372: 
        !           373: \texttt{~~~~~~~~if (\$pid =\~{} /\^{}A\textbackslash{}d\{8\}\$/)
1.1       raeburn   374: \{}
                    375: 
1.4     ! raeburn   376: \texttt{~~~~~~~~~~if (ref(\$multipids\{\$uname\}) eq 'ARRAY')
1.1       raeburn   377: \{}
1.4     ! raeburn   378: 
        !           379: \texttt{~~~~~~~~~~~~if (!grep(/\^{}\$pid\$/,@\{\$multipids\{\$uname\}\}))
1.1       raeburn   380: \{}
1.4     ! raeburn   381: 
        !           382: \texttt{~~~~~~~~~~~~~~push(@\{\$multipids\{\$uname\}\},\$pid);}
        !           383: 
        !           384: \texttt{~~~~~~~~~~~~\}}
        !           385: 
        !           386: \texttt{~~~~~~~~~~\} else \{}
        !           387: 
        !           388: \texttt{~~~~~~~~~~~~@\{\$multipids\{\$uname\}\} = (\$instusers->\{\$uname\}\{'id'\},\$pid);}
        !           389: 
        !           390: \texttt{~~~~~~~~~~\}}
        !           391: 
        !           392: \texttt{~~~~~~~~~~\$instusers->\{\$uname\}\{'id'\} = \$pid;}
        !           393: 
        !           394: \texttt{~~~~~~~~\}}
        !           395: 
        !           396: \texttt{~~~~~~\} elsif (\$instusers->\{\$uname\}\{'id'\} =\~{}
        !           397: /\^{}Z\textbackslash{}d\{8\}\$/) \{}
        !           398: 
        !           399: \texttt{~~~~~~~~if (\$pid =\~{} /\^{}Z\textbackslash{}d\{8\}\$/)
1.1       raeburn   400: \{}
                    401: 
1.4     ! raeburn   402: \texttt{~~~~~~~~~~if (ref(\$multipids\{\$uname\}) eq 'ARRAY')
1.1       raeburn   403: \{}
1.4     ! raeburn   404: 
        !           405: \texttt{~~~~~~~~~~~~if (!grep(/\^{}\$pid\$/,@\{\$multipids\{\$uname\}\}))
1.1       raeburn   406: \{}
1.4     ! raeburn   407: 
        !           408: \texttt{~~~~~~~~~~~~~~push(@\{\$multipids\{\$uname\}\},\$pid);}
        !           409: 
        !           410: \texttt{~~~~~~~~~~~~\}}
        !           411: 
        !           412: \texttt{~~~~~~~~~~\} else \{}
        !           413: 
        !           414: \texttt{~~~~~~~~~~~~@\{\$multipids\{\$uname\}\} = (\$instusers->\{\$uname\}\{'id'\},\$pid);}
        !           415: 
        !           416: \texttt{~~~~~~~~~~\}}
        !           417: 
        !           418: \texttt{~~~~~~~~\} elsif (\$pid =\~{} /\^{}A\textbackslash{}d\{8\}\$/)
1.1       raeburn   419: \{}
                    420: 
1.4     ! raeburn   421: \texttt{~~~~~~~~~~\$instusers->\{\$uname\}\{'id'\} = \$pid;}
        !           422: 
        !           423: \texttt{~~~~~~~~\}}
        !           424: 
        !           425: \texttt{~~~~~~\}}
        !           426: 
        !           427: \texttt{~~~~\}}
        !           428: 
        !           429: \texttt{~~\} else \{}
        !           430: 
        !           431: \texttt{~~~~\$instusers->\{\$uname\} = \{}
        !           432: 
        !           433: \texttt{~~~~~~firstname => \$first,}
        !           434: 
        !           435: \texttt{~~~~~~lastname => \$last,}
        !           436: 
        !           437: \texttt{~~~~~~id => \$pid,}
        !           438: 
        !           439: \texttt{~~~~~~permanentemail => \$uname.'@msu.edu', }
        !           440: 
        !           441: \texttt{~~~~~~inststatus => {[}\$type],}
        !           442: 
        !           443: \texttt{~~~~\};}
1.1       raeburn   444: 
1.4     ! raeburn   445: \texttt{~~\}}
1.1       raeburn   446: 
1.4     ! raeburn   447: \texttt{~~if (defined(\$instids->\{\$pid\})) \{}
1.1       raeburn   448: 
1.4     ! raeburn   449: \texttt{~~~~if (ref(\$instids->\{\$pid\}) eq 'ARRAY') \{}
1.1       raeburn   450: 
1.4     ! raeburn   451: \texttt{~~~~~~if (!grep(/\^{}\$uname\$/,@\{\$instids->\{\$pid\}\}))
1.1       raeburn   452: \{}
1.4     ! raeburn   453: 
        !           454: \texttt{~~~~~~~~push(@\{\$instids->\{\$pid\}\},\$uname);}
        !           455: 
        !           456: \texttt{~~~~~~\}}
        !           457: 
        !           458: \texttt{~~~~\} elsif (\$instids->\{\$pid\} ne \$uname) \{}
        !           459: 
        !           460: \texttt{~~~~~~@\{\$instids->\{\$pid\}\} = (\$instids->\{\$pid\},\$uname);}
        !           461: 
        !           462: \texttt{~~~~\}}
        !           463: 
        !           464: \texttt{~~\} else \{}
        !           465: 
        !           466: \texttt{~~~~\$instids->\{\$pid\} = \$uname;}
        !           467: 
        !           468: \texttt{~~\}}
        !           469: 
1.1       raeburn   470: \texttt{\}}
                    471: 
                    472: \texttt{\$outcome = 'ok';}
                    473: \end{quotation}
                    474: \texttt{\}}
                    475: \end{quotation}
                    476: \texttt{\}}
                    477: 
                    478: \texttt{if (\$ldapfilter ne '') \{}
                    479: \begin{quotation}
                    480: \texttt{my \$ldapres = \&ldap\_search(\$ldapfilter,\$instusers,\$types);}
                    481: 
                    482: \texttt{if (!\$dbflag) \{}
                    483: \begin{quotation}
                    484: \texttt{\$outcome = \$ldapres;}
                    485: \end{quotation}
                    486: \texttt{\}}
                    487: \end{quotation}
                    488: \texttt{\}}
                    489: 
                    490: \texttt{return \$outcome;}
                    491: \end{quotation}
                    492: \texttt{\}}
                    493: \end{quotation}
                    494: At MSU, a search of the LDAP directory is used to supplement SQL queries
                    495: of Faculty, Staff and Student database tables, because there are no
                    496: student/employee IDs available from MSU's LDAP service. The LDAP search
                    497: is used to retrieve information about users who have MSUNetIDs (i.e.,
1.3       raeburn   498: official usernames from MSU), but are not currently affiliated with
1.1       raeburn   499: any of the institutional user types, so are absent from the six SQL
                    500: database tables.
                    501: 
                    502: \begin{quotation}
                    503: \texttt{sub ldap\_search \{}
                    504: \begin{quotation}
                    505: \texttt{my (\$ldapfilter,\$instusers,\$types) = @\_;}
                    506: 
                    507: \texttt{my \$outcome;}
                    508: 
                    509: \texttt{my \$ldap = Net::LDAP->new( 'ldap.msu.edu' );}
                    510: 
                    511: \texttt{if (\$ldap) \{}
                    512: \begin{quotation}
                    513: \texttt{\$ldap->bind;}
                    514: 
                    515: \texttt{my \$mesg = \$ldap->search(}
                    516: \begin{quotation}
                    517: \texttt{base => \char`\"{}dc=msu, dc=edu\char`\"{},}
                    518: 
                    519: \texttt{filter => \$ldapfilter,}
                    520: 
                    521: \texttt{attrs => {[}'sn','givenName','title','uid','mail','employeeType'],}
                    522: \end{quotation}
                    523: \texttt{);}
                    524: 
                    525: \texttt{if (\$mesg->code) \{}
                    526: \begin{quotation}
                    527: \texttt{\$ldap->unbind;}
                    528: 
                    529: \texttt{return;}
                    530: \end{quotation}
                    531: \texttt{\} else \{}
                    532: \begin{quotation}
                    533: \texttt{\$outcome = 'ok';}
                    534: \end{quotation}
                    535: \texttt{\}}
                    536: 
                    537: \texttt{foreach my \$entry (\$mesg->entries) \{}
                    538: \begin{quotation}
                    539: \texttt{my \$uname = \$entry->get\_value('uid');}
                    540: 
                    541: \texttt{next if (\$uname eq '');}
                    542: 
                    543: \texttt{my \$first = \$entry->get\_value('givenName');}
                    544: 
                    545: \texttt{my \$last = \$entry->get\_value('sn');}
                    546: 
                    547: \texttt{my \$email = \$entry->get\_value('mail');}
                    548: 
                    549: \texttt{my \$type;}
                    550: 
                    551: \texttt{if ((\$entry->get\_value('employeeType') eq 'Faculty') ||
                    552: (\$entry->get\_value('employeeType') eq 'Staff')) \{}
                    553: \begin{quotation}
                    554: \texttt{\$type = \$entry->get\_value('employeeType');}
                    555: \end{quotation}
                    556: \texttt{\} elsif (\$entry->get\_value('title') eq 'Student') \{}
                    557: \begin{quotation}
                    558: \texttt{\$type = \$entry->get\_value('title');}
                    559: \end{quotation}
                    560: \texttt{\}}
                    561: 
                    562: \texttt{if (ref(\$types) eq 'ARRAY') \{}
1.4     ! raeburn   563: 
        !           564: \texttt{~~if (@\{\$types\} > 0) \{}
1.1       raeburn   565: \begin{quotation}
1.4     ! raeburn   566: \texttt{~~if ((\$type ne '') \&\& !(grep(/\^{}\$type\$/,@\{\$types\}))) }
        !           567: 
        !           568: \texttt{~~~~next if (!grep(/\^{}default\$/,@\{\$types\}));}
        !           569: 
        !           570: \texttt{~~\}}
        !           571: 
        !           572: \texttt{~~next if ((\$type eq '') \&\& (!grep(/\^{}default\$/,@\{\$types\})));}
1.1       raeburn   573: 
                    574: \texttt{\}}
                    575: \end{quotation}
                    576: \texttt{\}}
                    577: 
                    578: \texttt{if (ref(\$instusers->\{\$uname\}) eq 'HASH') \{}
1.4     ! raeburn   579: 
        !           580: \texttt{~~if (ref(\$instusers->\{\$uname\}\{'inststatus'\}) eq 'ARRAY')
1.1       raeburn   581: \{}
1.4     ! raeburn   582: 
        !           583: \texttt{~~~~if (!grep(/\^{}\$type\$/,@\{\$instusers->\{\$uname\}\{'inststatus'\}\}))
1.1       raeburn   584: \{}
1.4     ! raeburn   585: 
        !           586: \texttt{~~~~~~push(@\{\$instusers->\{\$uname\}\{'inststatus'\}\},\$type);}
        !           587: 
        !           588: \texttt{~~~~\}}
        !           589: 
        !           590: \texttt{~~\}}
        !           591: 
1.1       raeburn   592: \texttt{\} else \{}
                    593: 
1.4     ! raeburn   594: \texttt{~~\$instusers->\{\$uname\} = \{}
        !           595: 
        !           596: \texttt{~~firstname => \$first,}
        !           597: 
        !           598: \texttt{~~lastname => \$last,}
        !           599: 
        !           600: \texttt{~~id => '',}
1.1       raeburn   601: 
1.4     ! raeburn   602: \texttt{~~permanentemail => \$email,}
1.1       raeburn   603: 
1.4     ! raeburn   604: \texttt{~~inststatus => {[}\$type],}
1.1       raeburn   605: 
                    606: \texttt{\};}
                    607: \end{quotation}
                    608: \texttt{\}}
                    609: 
                    610: \texttt{\$ldap->unbind;}
                    611: \end{quotation}
                    612: \texttt{\}}
                    613: 
                    614: \texttt{return \$outcome;}
                    615: \end{quotation}
                    616: \texttt{\}}
                    617: \end{quotation}
                    618: \textbf{\large allusers\_info}{\large \par}
                    619: 
                    620: Three arguments are required:
                    621: 
                    622: \begin{enumerate}
                    623: \item \$dom - domain
                    624: \item \$instusers - reference to hash which will contain hashes, where keys
                    625: will be usernames and value will be a hash of user information. 
                    626: 
                    627: 
                    628: Keys in the inner hash will be some or all of: lastname, firstname,
                    629: middlename, generation, id, inststatus - institutional status (e.g.,
                    630: faculty,staff,student)
                    631: 
                    632: Values are all scalars except inststatus, which is an array.
                    633: 
                    634: \item \$instids - reference to hash which will contain ID numbers. keys
                    635: will be unique IDs (student or faculty/staff ID).
                    636: 
                    637: 
                    638: Values will be either: scalar (username) or an array if a single ID
                    639: matches multiple usernames.
                    640: 
                    641: \end{enumerate}
                    642: Returns 'ok' if no error occurred.
                    643: 
                    644: Side effects - populates the \$instusers and \$instids refs to hashes
                    645: with information for all users from all available institutional datafeeds.
                    646: 
                    647: In the MSU case, six SQL database tables are queried via the \emph{query\_user\_tables()}
                    648: routine described above. 
                    649: 
                    650: \begin{quotation}
                    651: \texttt{sub allusers\_info \{}
                    652: \begin{quotation}
                    653: \texttt{my (\$dom,\$instusers,\$instids) = @\_;}
                    654: 
                    655: \texttt{my \$outcome;}
                    656: 
                    657: \texttt{my (\$dbh,\$dbflag) = \&connect\_DB('HR');}
                    658: 
                    659: \texttt{if (\$dbflag) \{}
                    660: \begin{quotation}
                    661: \texttt{my @srchtables = ('FACULTY\_VU','STAFF\_VU','STUDENT','AFFILIATE','ASSISTANT','STUDENT\_AFFILIATE');}
                    662: 
                    663: \texttt{\&query\_user\_tables(\$dbflag,\$dbh,\textbackslash{}@srchtables,\$instusers,\$instids);}
                    664: 
                    665: \texttt{\$outcome = 'ok';}
                    666: 
                    667: \texttt{\&disconnect\_DB(\$dbh);}
                    668: \end{quotation}
                    669: \texttt{\}}
                    670: 
                    671: \texttt{return \$outcome;}
                    672: \end{quotation}
                    673: \texttt{\}}
                    674: \end{quotation}

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>