Accounts API¶
This is the documentation for the Python client for the MaIS Accounts API.
Everything you need is available in the stanford.mais.account.account
module.
To begin using the MaIS Accounts API, you should first instantiate a
MAISClient
object. Once that is done, you can
use it to instantiate an AccountClient
object.
Account API Client¶
You will use the AccountClient
instance to
access the API. Once that is done, you can use the
get()
method to access
Accounts.
- class stanford.mais.account.AccountClient(client: stanford.mais.client.MAISClient, custom_session: Optional[requests.sessions.Session] = None, _cache: MutableMapping[str, stanford.mais.account.account.Account] = <factory>)[source]¶
The
AccountClient
is the first thing you will instantiate when you want to interact with the MaIS Account API. One parameter is required to instantiate a client.- Parameters
client (stanford.mais.client.MAISClient) – The MAIS client to use.
Once you have a client instantiated, you can use
get()
to fetch an account. For your convenience, instances of this class also implement__getitem__
, so instead of doing…aclient = AccountClient(...) lelandjr = client.get('lelandjr')
… you can do …
aclient = AccountClient(...) lelandjr = client['lelandjr']
Instances also implement
Container
functionality, so you can check for account existence like so:aclient = AccountClient(...) lelandjr_exists = (True if 'lelandjr' in aclient else False)
Through the use of caching, if you then decide to fetch the account after confirming its existance, the entry will be served from cache instead of making a fresh API request.
Warning
The existence of an account does not mean it is active!
- client: stanford.mais.client.MAISClient¶
A
MAISClient
instance.This configures the API endpoint (accessed via
client.urls['account']
) and client key/cert to use. It must be provided when calling the class constructor.- Raises
TypeError – A client was not provided.
- session: requests.sessions.Session¶
The Requests Session to use for API requests.
This session container pre-configures our requests, including client certificate, timeouts, and headers.
Normally, this should not be set, and a new session will be requested from the client. But if you would like to use a custom
Session
instance (such as for mock testing), provide it to the constructor as thecustom_session
and it will be used for all requests.
- get(sunetid: str) → stanford.mais.account.account.Account[source]¶
Fetch an Account.
This is a convenience wrapper around
Account.get()
. All other parameters provided are passed through toget()
, and the resulting instance is returned.Refer to
Account.get()
for details on parameters, exceptions, etc..
- only_active() → stanford.mais.account.AccountView[source]¶
Create a modified :class:
AccountClient
that can only see active accounts.The returned client instance has been modified so that
get()
only returns active accounts. If you try to look up an inactive account,get()
will act as if the account does not exist.As many Account API consumers are only interested in active accounts, you may find this to be very convenient. If this interests you, you can do something like this:
import stanford.mais.client from stanford.mais.client.account import AccountClient api_client = stanford.mais.client.MAISClient(...) active_accounts = AccountClient(api_client).only_active()
Warning
The ‘client’ returned by this method uses the same caches as this client. Therefore, it must not be used across threads/processes.
- only_inactive() → stanford.mais.account.AccountView[source]¶
Create a modified :class:
AccountClient
that can only see inactive accounts.The returned client instance has been modified so that
get()
only returns inactive accounts. If you try to look up an active account,get()
will act as if the account does not exist.Warning
The ‘client’ returned by this method uses the same caches as this client. Therefore, it must not be used across threads/processes.
- only_people() → stanford.mais.account.AccountView[source]¶
Create a modified :class:
AccountClient
that can only see accounts of people.The returned client instance has been modified so that
get()
only returns the accounts of people. If you try to look up a functional account,get()
will act as if the account does not exist.As many Account API consumers are only interested in SUNetIDs, you may find this to be very convenient. If this interests you, you can do something like this:
import stanford.mais.client from stanford.mais.client.account import AccountClient api_client = stanford.mais.client.MAISClient(...) sunetids = AccountClient(api_client).only_people()
And, if you only care about active SUNetIDs, you can chain them together, like this:
import stanford.mais.client from stanford.mais.client.account import AccountClient api_client = stanford.mais.client.MAISClient(...) active_sunetids = AccountClient(api_client).only_active().only_people()
Warning
The ‘client’ returned by this method uses the same caches as this client. Therefore, it must not be used across threads/processes.
- only_functional() → stanford.mais.account.AccountView[source]¶
Create a modified :class:
AccountClient
that can only see functional accounts.The returned client instance has been modified so that
get()
only returns functional accounts. If you try to look up a person’s account (a SUNetID),get()
will act as if the account does not exist.Warning
The ‘client’ returned by this method uses the same caches as this client. Therefore, it must not be used across threads/processes.
Account¶
Once you have a Account API client instance, you will be fetching
Account
instances.
All account attributes will be found within the
Account
instance. Service-specific information
will be found within the services()
dict, which will present a different interface depending on the service.
Read more about services.
- class stanford.mais.account.Account(client: AccountClient, sunetid: str, name: str, description: str, is_person: bool, is_active: bool, is_full: bool, services: stanford.mais.account.account.AccountServiceTypes, last_updated: datetime.datetime, raw: dict)[source]¶
A SUNetID Account.
The entire contents are read-only.
Note
Information from the Account API is generally mapped to attributes in the Accounts Tree in Stanford LDAP.
- client: AccountClient¶
The
AccountClient
representing the API endpoint we are using.
- sunetid: str¶
The SUNetID, for people; for functional accounts, the ID. This is the id key from the API.
Note
This is used as the account’s
uid
in LDAP.
- name: str¶
For people, this is ther name (last name first). For functional accounts, this is a name set at the time of account creation. This is the name key from the API.
- description: str¶
For people, this is a combination of their Org name and their position title. This may be set to “Former …” or the like for inactive accounts For functional accounts, this is a description set at the time of account creation. This is the description key from the API.
Note
This is used as the account’s
description
in LDAP.
- is_person: bool¶
If True, this account is for a person. If False, this account is for a “functional account”. This is the type key from the API.
- is_active: bool¶
If True, this SUNetID is active. In other words, someone could authenticate to Stanford Login using this SUNetID. This does not imply anything else. This is computed from the status key from the API.
- is_full: bool¶
If True, this is a full SUNetID. That means the SUNetID has services like email enabled. A SUNetID can be “full” either by being associated with an active student, faculty, or staff member; or via sponsorship. NOTE: Some services (such as Library e-resources) are not available to all Full SUNetIDs, so this property does not imply access to all services.
- services: stanford.mais.account.account.AccountServiceTypes¶
This contains the services currently associated with the account. Each service has a service name, and the value is a dataclass which contains status and service-specific information.
It is a
Mapping
ofstr
(the service name) to subclasses ofAccountService
. To learn the key name for each service, refer to the documentation for that subclass.Note
From time to time, new services are defined. Those services will not appear in this mapping until a software update is released, defining a new subclass for that service. If you need to access the service’s data before that time, refer to the services key in the parsed JSON.
- last_updated: datetime.datetime¶
The datetime when the account was last updated. It is timezone-aware, and is already set to the UTC timezone.
- raw: dict¶
This is the parsed JSON returned from the MaIS Accounts API. Most keys have already been parsed, and are available as properties. Here are some additional keys you can find:
owner: This is a string with two parts, with a forward-slash used as a separator.
If the account is for a person (that is, type is “self”), then this string will be
person/
followed by the RegID of the person.If the account is for a functional account (type is “functional”), then this string will be
organization/
followed by the RegID of the Org which owns the functional account.
statusDate: The date when this account was last changed, in the US/Pacific time zone, in the form of a POSIX timestamp tht has been multiplied by 1,000 and microseconds added on to the end. You can parse this using
datetime.datetime.fromtimestamp()
and the third-partypytz.timezone()
as follows:statusDateInt=account.raw['statusDate'] statusDate=datetime.datetime.fromtimestamp( statusDateInt//(10**3), tz=pytz.timezone('US/Pacific') ).replace( microsecond=statusDateInt%(10**3) ).astimezone( pytz.utc )
You really should just use
last_updated()
instead.
- classmethod get(client: AccountClient, sunetid: str) → Account[source]¶
Given a string, return an Account.
This uses the MaIS Workgroup API to look up information for an account, using the SUNetID as input.
This function is memoized; once a lookup is performed, subsequent calls for the same input will return the same result instance, thanks to the use of a cache.
Warning
This will looks up accounts of all types, both accounts for people and also functional accounts. Check
is_person()
before assuming you are working with a SUNetID.Warning
This memoization means that, should an account change status after lookup, that status change will not be noticed until after the module is reloaded. That means this code should not be used by long-running client code.
- Parameters
client – An
AccountClient
representing our API endpoint.sunetid – The ID to look up. This must be an actual id, not an alias.
- Raises
ChildProcessError – Something went wrong on the server side (a 400 or 500 error was returned).
KeyError – The given ID does not exist. Maybe it was an alias?
PermissionError – You did not use a valid certificate, or do not have permissions to perform the operation.
UnicodeEncodeError – The ID you provided included non-ASCII characters.
ValueError – The input contains non-ASCII characters.
requests.Timeout – The MaIS Workgroup API did not respond in time.
Account Services¶
Accounts normally have at least one service attached. For example, active
accounts have a kerberos
service active. Even inactive accounts might have
services attached, although those services will all be inactive.
Services are accessed through
services()
, like so:
aclient = stanford.mais.account.AccountClient(...)
lelandjr = aclient['lelandjr']
if lelandjr.services.kerberos is None:
lelandjr_uid = None
else:
lelandjr_uid = lelandjr.services.kerberos.uid
services()
acts as a named tuple, with an
attribute for each service that the Python MsIS Account API client is aware of.
Through these attributes, you can access service status and
service-specific settings. For example, the kerberos
service maps to the
AccountServiceKerberos
class.
If an account does not have a service defined, accessing that attribute will
return None
.
Note
When an account is a functional account, and not an account for a person,
there is no guarantee what services will be enabled. For example, a
functional account used for a web site’s CGI space will have kerberos
,
pts
, and possibly afs
service; a functional account used for shared
email will not have any of those, but will have seas
service.
Warning
When a service is active, some service-specific settings are guaranteed to be present, and some are optional. However, when a service is not active, all service-specific settings become optional.
- class stanford.mais.account.service.AccountService(name: str, is_active: bool)[source]¶
Represents an account service.
This is a base container representing a service, and stores the common properties that a service can have. For service-specific properties, check out the documentation for the appropriate subclasses.
- class stanford.mais.account.service.AccountServiceKerberos(name: str, is_active: bool, principal: str, uid: int)[source]¶
kerberos
service for an Account.This represents an account’s entry in Kerberos. If active, then the account is at least a base (or base-sponsored) account.
- class stanford.mais.account.service.AccountServiceLibrary(name: str, is_active: bool)[source]¶
library
service for an Account.New as of 2019, this represents access to Library e-resources. It has no known settings, and you should not assume that having this enabled means the account is full or full-sponsored.
- class stanford.mais.account.service.AccountServiceSEAS(name: str, is_active: bool, local: str, sunetid: str, sunetidpreferred: str, forward: str, urirouteto: str)[source]¶
seas
service for an Account.The “Stanford Electronic Alias Service”. If this service is active, then the account has an associated @stanford.edu email address, even if they don’t have a Stanford email box.
Note
Even though they include a shared mailbox, Shared Email functional accounts have
seas
service, but notemail
service.- local: str¶
This is an optional setting. If the account has a Stanford email box, and the account wants emails delivered to that mailbox, then this is the this is the canonical email address for that mailbox.
Warning
Do not try to send emails directly to this email address.
- sunetid: str¶
This is a setting which may appear multiple times. Each entry represents an @stanford.edu email address. There will always be one entry matching the account’s ID (so that id@stanford.edu works). If the user has any email alises, each alias will appear as an additional entry.
- sunetidpreferred: str¶
This is the alias that the user prefers to use as their ID in their Stanford email address. If the user does not have any aliases, then this will be their account ID.
Note
This setting, along with the tier-specific suffix (
@stanford.edu
on PROD), is used for the user’smail
attribute in LDAP (in thepeople
tree).
- forward: str¶
This is an optional setting. If present, emails received by this address will be forwarded to the emails listed in this setting. Multiple emails are separated by a comma.
Warning
Do not try to send emails directly to this email address.
- urirouteto: str¶
When a client browses to https://stanford.edu/~id, this is the URI where the client will be redirected. If it is just a path (and not a full URL), it is relative to https://web.stanford.edu/.
- class stanford.mais.account.service.AccountServiceEmail(name: str, is_active: bool, accounttype: str, quota: int, admin: str)[source]¶
email
service for an Account.This represents a Stanford mailbox. If active, the account has a Stanford electronic mailbox. The
seas
service should also be present and active.Note
The specific email backend (Zimbra, Office 365, Google, …) is not indicated.
- class stanford.mais.account.service.AccountServiceAutoreply(name: str, is_active: bool, forward: str, subj: str, msg: str)[source]¶
autoreply
service for an Account.This represents the email autoresponder service. If active, incoming emails will be forwarded to the autoresponder service, which will send an appropriate reply.
- forward: str¶
The account’s canonical email address in the autoresponder system.
Warning
Do not try to send emails directly to this email address.
- class stanford.mais.account.service.AccountServiceLeland(name: str, is_active: bool, shell: str)[source]¶
leland
service for an Account.This represents the Stanford Shared Computing environment, once known as Leland and known today as FarmShare. If active, users are able to log in to FarmShare.
Note
Full and full-sponsored accounts have this active; base and base-sponsored account do not. Functional accounts never have this active.
- class stanford.mais.account.service.AccountServicePTS(name: str, is_active: bool, uid: int)[source]¶
pts
service for an Account.This represents an account’s entry in the AFS Protection Server’s database. An account must have an entry here in order to access any AFS services.
- class stanford.mais.account.service.AccountServiceAFS(name: str, is_active: bool, homedirectory: str)[source]¶
afs
service for an Account.This represents an account’s AFS home directory.
- homedirectory: str¶
The path to the account’s home directory.
Note
This is used as the account’s
homeDirectory
in LDAP. As such, you will probably want to override it.Note
This setting assumes that AFS is mounted at path
/afs
on a ssytem. This is normally, but not always, the case. This setting also assumes that your system has an up-to-date copy of the CellServDB file, which should be the case if you are using a packaged OpenAFS client.
- class stanford.mais.account.service.AccountServiceDialin(name: str, is_active: bool)[source]¶
dialin
service for an Account.This represented the Stanford UIT dial-in modem pools, which had various phone numbers, including +1 (415) 498-1440 (this was before area code 650) and +1 (650) 325-1010. If this service was active, you had access to the pool. It has no settings, and should not be used. If may disappear in the future.
Accounts Validation¶
The Account
class provides all of the tools
needed to validate a single SUNetID (that is, determine if it is a valid
SUNetID). But if you have a list of SUNetIDs (particularly an unformatted
list), the stanford.mais.account.validate
module has function that can
help.
- stanford.mais.account.validate.validate(raw: str, client: stanford.mais.account.AccountClient) → stanford.mais.account.validate.AccountValidationResults[source]¶
- stanford.mais.account.validate.validate(raw: Union[List[str], Tuple[str], Set[str]], client: stanford.mais.account.AccountClient) → stanford.mais.account.validate.AccountValidationResults
- stanford.mais.account.validate.validate(raw: Union[List[str], Tuple[str], Set[str]], client: stanford.mais.account.AccountClient) → stanford.mais.account.validate.AccountValidationResults
- stanford.mais.account.validate.validate(raw: Union[List[str], Tuple[str], Set[str]], client: stanford.mais.account.AccountClient) → stanford.mais.account.validate.AccountValidationResults
Given a list of SUNetIDs; as a string or a list, tuple, or set; validate and check status.
This takes a list of SUNetIDs, and returns a list of SUNetIDs which have been checked against the Accounts API for both activity and service level. The returned result shows which SUNetIDs are active full (or full-sponsored), active base (or base-sponsored), or inactive.
If the input is a string, then the input string may be separated by commas, and/or whitespace, (where “whitespace” is a space, newline/linefeed, form feed, carriage return, tab/horizontal tab, or vertical tab character). If the input is a list, tuple, or set; the function assumes that all whitespace etc. have been removed.
Note
“List, tuple, or set” is used instead of the generic “collection” because a
str
is also a collection (of otherstr
). See typing issue #256 for the discussion around this issue.This is designed to catch most exceptions. Exceptions related to validation (for example, attempting to validate an obviously-invalid SUNetID like ab$#) will result in the ‘SUNetID’ being added to the unknown list, instead of throwing an exception. The only exceptions that should be expected from this function are ones related to API issues.
- Parameters
raw – The list of SUNetIDs. If a str, then the list may be comma- and/or whitespace-separated.
client – An
AccountClient
to connect to the Account API.
- Returns
The results of the validation. See the definition of
AccountValidationResults
for details. If the input to this function is a string; that string will be in raw, and the parsed list will be in raw_set. If the input to this function is not a string, then raw will be None and raw_set will be a copy of the input.- Raises
ChildProcessError – Something went wrong on the server side (a 400 or 500 error was returned).
PermissionError – You did not use a valid certificate, or do not have permissions to perform the operation.
requests.Timeout – The MaIS Workgroup API did not respond in time.
- class stanford.mais.account.validate.AccountValidationResults(raw: Optional[str], raw_set: Collection[str], full: Collection[str], base: Collection[str], inactive: Collection[str], unknown: Collection[str])[source]¶
Results of doing an account validation.
This class contains the results of an account validation, called via
validate()
.Note
Many of these properties are collections. That means, if you want to use things like subscripting, you will want to convert to a more-specific type (such as
list
before using it).- raw: Optional[str]¶
The raw input provided for validation. This is only provided when a string was provided to
validate()
.
- raw_set: Collection[str]¶
The raw input provided for validation. If a string was provided to
validate()
, then this is the raw input after being split into a collection. Otherwise, this will be the original list/set/tuple that was provided tovalidate()
, but made into a set.The set union of full, base, inactive, and unknown is equal to this list.