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

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}
1.5     ! raeburn   152: \texttt{\$outcome = \&query\_user\_tables(\$dbflag,\$dbh,\textbackslash{}@srchtables,}
1.1       raeburn   153: \begin{quotation}
1.5     ! raeburn   154: \texttt{~~~~~~~\$instusers,\$instids,\$srchby,\$srchterm,\$srchtype,\$types);}
1.1       raeburn   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}
1.5     ! raeburn   175: \texttt{my (\$dbflag,\$dbh,\$srchtables,\$instusers,\$instids,\$srchby,\$srchterm,}
        !           176: \texttt{~~~~\$srchtype,\$types) = @\_;}
1.1       raeburn   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: 
1.5     ! raeburn   287: \texttt{my \$statement = \char`\"{}SELECT MSUNetID,Pid,FirstName,LastName,}
        !           288: \texttt{~~~~~~~~~~~~~~~~~Person\_Type FROM \$table \$condition\char`\"{};}
1.4       raeburn   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: 
1.5     ! raeburn   388: \texttt{~~~~~~~~~~~~@\{\$multipids\{\$uname\}\}=(\$instusers->\{\$uname\}\{'id'\},\$pid);}
1.4       raeburn   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: 
1.5     ! raeburn   414: \texttt{~~~~~~~~~~~~@\{\$multipids\{\$uname\}\}=(\$instusers->\{\$uname\}\{'id'\},\$pid);}
1.4       raeburn   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}
1.5     ! raeburn   661: \texttt{my @srchtables = ('FACULTY\_VU','STAFF\_VU','STUDENT','AFFILIATE',}
        !           662: \texttt{~~~~~~~~~~~~~~~~~~'ASSISTANT','STUDENT\_AFFILIATE');}
1.1       raeburn   663: 
                    664: \texttt{\&query\_user\_tables(\$dbflag,\$dbh,\textbackslash{}@srchtables,\$instusers,\$instids);}
                    665: 
                    666: \texttt{\$outcome = 'ok';}
                    667: 
                    668: \texttt{\&disconnect\_DB(\$dbh);}
                    669: \end{quotation}
                    670: \texttt{\}}
                    671: 
                    672: \texttt{return \$outcome;}
                    673: \end{quotation}
                    674: \texttt{\}}
                    675: \end{quotation}

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