diff --git a/.gitignore b/.gitignore index 8e5f25d..e0073cf 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ __pycache__/ *.o *.so .idea/ +/docs/*.1 +/docs/*.5 diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..64aadda --- /dev/null +++ b/docs/README.md @@ -0,0 +1,23 @@ +# Documentation +## OpenAPI +We are using [OpenAPI 3.0](https://swagger.io/docs/specification/about/) to +document the REST API for ceod, and [Redoc](https://github.com/Redocly/redoc) +to generate HTML documentation from the OpenAPI file. + +First, make sure you have Node.js and npm installed. Then, install the Redoc CLI: +```sh +npm install -g redoc-cli +``` +After you make changes to the openapi.yaml file, make sure to regenerate the HTML: +```sh +redoc-cli bundle openapi.yaml +``` +You can now view the [redoc-static.html](./redoc-static.html) file from your browser. + +## Man pages +We are using [scdoc](https://git.sr.ht/~sircmpwn/scdoc) to generate our man pages. +You can view the pages from your terminal like so: +```sh +scdoc < ceo.1.scd > ceo.1 +man ./ceo.1 +``` diff --git a/docs/ceo.1.scd b/docs/ceo.1.scd new file mode 100644 index 0000000..08f3b26 --- /dev/null +++ b/docs/ceo.1.scd @@ -0,0 +1,29 @@ +ceo(1) + +# NAME + +ceo - CSC Electronic Office + +# SYNOPSIS + +*Text User Interface* + *ceo* + +*Command Line Interface* + *ceo* [OPTIONS] COMMAND [ARGS]... + +# DESCRIPTION +CSC Electronic Office is used to manage membership registration and user accounts for the Computer Science Club. + +To use the TUI, type *ceo* with no arguments. +To use the CLI, run *ceo --help*. + +# SEE ALSO + +*ceo.ini*(5), *ceod.ini*(5) + +# AUTHORS + +Max Erenberg ++ +Andrew Wang ++ +Rio Liu diff --git a/docs/ceo.ini.5.scd b/docs/ceo.ini.5.scd new file mode 100644 index 0000000..1b823bc --- /dev/null +++ b/docs/ceo.ini.5.scd @@ -0,0 +1,57 @@ +ceo.ini(5) + +# NAME + +ceo.ini - configuration file for ceo + +# SYNOPSIS + +/etc/csc/ceo.ini + +# DESCRIPTION + +ceo.ini is an INI file with various sections which control the behaviour of *ceo*(1). + +# DEFAULTS SECTION + _base_domain_++ + The domain name of CSC. Should be set to 'csclub.uwaterloo.ca'. + + _uw_domain_++ + The domain of UW. Should be set to 'uwaterloo.ca'. + +# CEOD SECTION + _admin_host_++ + The host with the ceod/admin Kerberos key. + + _database_host_++ + The host with the root password for MySQL and PostgreSQL. + + _mailman_host_++ + The host running Mailman. + + _use_https_++ + Whether to use HTTPS when connecting to ceod. Should be set to 'true'. + + _port_++ + The port on which ceod is listening. + +# POSITIONS SECTION + _required_++ + A comma-separated list of executive positions which must be fulfilled. + + _available_++ + A comma-separated list of available executive positions. + +# MYSQL SECTION + _host_++ + The host where MySQL is running. + +# POSTGRESQL SECTION + _host_++ + The host where PostgreSQL is running. + +# SEE ALSO +*ceo*(1) + +# AUTHORS +Max Erenberg diff --git a/docs/ceod.ini.5.scd b/docs/ceod.ini.5.scd new file mode 100644 index 0000000..e713199 --- /dev/null +++ b/docs/ceod.ini.5.scd @@ -0,0 +1,159 @@ +ceod.ini(5) + +# NAME + +ceod.ini - configuration file for ceod + +# SYNOPSIS + +/etc/csc/ceod.ini + +# DESCRIPTION + +ceod.ini is an INI file with various sections which control the behaviour of ceod. + +# DEFAULTS SECTION + _base_domain_++ + The domain name of CSC. Should be set to 'csclub.uwaterloo.ca'. + +# CEOD SECTION + _admin_host_++ + The host with the ceod/admin Kerberos key. + + _fs_root_host_++ + The host without NFS root squashing. + + _database_host_++ + The host with the root password for MySQL and PostgreSQL. + + _mailman_host_++ + The host running Mailman. + + _use_https_++ + Whether to use HTTPS when connecting to ceod. Should be set to 'true'. + + _port_++ + The port on which ceod is listening. + +# LDAP SECTION + _admin_principal_++ + The Kerberos principal which ceod should use for *kadmin*(1). + + _server_url_++ + The primary CSC LDAP server URL. + + _sasl_realm_++ + The CSC SASL realm for LDAP. Should be 'CSCLUB.UWATERLOO.CA'. + + _users_base_++ + The LDAP OU where users are stored. + + _groups_base_++ + The LDAP OU where groups are stored. + + _sudo_base_++ + The LDAP OU where *sudo*(8) roles are stored. + +# UWLDAP SECTION + _server_url_++ + The UW LDAP server URL. + + _base_++ + The LDAP OU where users are stored in the UW LDAP. + +# MEMBERS SECTION + _min_id_++ + The minimum UID number for members. + + _max_id_++ + The maximum UID number for members. + + _home_++ + The directory in which new members' home directories should be created. + + _skel_++ + The skeleton directory for new members. + +# CLUBS SECTION + _min_id_++ + The minimum UID number for club accounts. + + _max_id_++ + The maximum UID number for club accounts. + + _home_++ + The directory in which new club accounts' home directories should be created. + + _skel_++ + The skeleton directory for new club accounts. + +# MAIL SECTION + _smtp_url_++ + The SMTP URL where ceod should send emails. + + _smtp_starttls_++ + Whether ceod should use STARTTLS with the SMTP server or not. + +# MAILMAN3 SECTION + _api_base_url_++ + The base URL of the Mailman 3 API. + + _api_username_++ + The username to use when authenticating to the Mailman 3 API via HTTP Basic Auth. + + _api_password_++ + The password to use when authenticating to the Mailman 3 API via HTTP Basic Auth. + + _new_member_list_++ + The mailing list to which new members should be subscribed. + +# AUXILIARY GROUPS SECTION + Each key in this section contains a comma-separated list of auxiliary groups to + which members should be added when joining the primary group. For example, + + syscom = office,staff + + means that when someone joins the syscom group, they will also be added to the + office and staff groups. + +# AUXILIARY MAILING LISTS SECTION + Each key in this section contains a comma-separated list of auxiliary mailing lists to + which members should be subscribed when joining the primary group. For example, + + syscom = syscom,syscom-alerts + + means that when someone joins the syscom group, they will also be subscribed to the + syscom and syscom-alerts mailing lists. + +# POSITIONS SECTION + _required_++ + A comma-separated list of executive positions which must be fulfilled. + + _available_++ + A comma-separated list of available executive positions. + +# MYSQL SECTION + _host_++ + The host where MySQL is running. + + _username_++ + The username to use when connecting to MySQL. + + _password_++ + The password to use when connecting to MySQL. + +# POSTGRESQL SECTION + _host_++ + The host where PostgreSQL is running. + + _username_++ + The username to use when connecting to PostgreSQL. + + _password_++ + The password to use when connecting to PostgreSQL. + +# SEE ALSO +*ceo.ini*(5) + +# AUTHORS +Max Erenberg diff --git a/docs/openapi.yaml b/docs/openapi.yaml new file mode 100644 index 0000000..4ba25bd --- /dev/null +++ b/docs/openapi.yaml @@ -0,0 +1,861 @@ +openapi: 3.0.0 +info: + title: ceod - OpenAPI 3.0 + description: | + This is an OpenAPI specification of ceod, the CSC Electronic Office daemon. + Visit the [git repository](https://git.csclub.uwaterloo.ca/public/pyceo) for + more details. + ## Streaming Responses + Many endpoints return a "streaming response", which consists of a series of JSON + objects, one per line (the mimetype is text/plain). For example: + ``` + {"status": "in progress", "operation": "replace_login_shell"} + {"status": "in progress", "operation": "replace_forwarding_addresses"} + {"status": "completed", "result": "OK"} + ``` + Whenever an operation is completed, a corresponding JSON object will be streamed + from the server to the client. This allows the client to track the server's progress + in real time. + contact: + email: syscom@csclub.uwaterloo.ca + version: 1.0.0 +servers: +- url: https://phosphoric-acid.csclub.uwaterloo.ca:9987/api +tags: +- name: members + description: Operations on members and club reps +- name: groups + description: Operations on groups and clubs +- name: mailman + description: Operations on mailing list subscriptions +- name: uwldap + description: Operations related to the UW LDAP directory +- name: database + description: Operations related to databases +security: +- GSSAPIAuth: [] +paths: + /members: + post: + tags: ['members'] + summary: Create a new user + description: >- + Creates a new member or club rep. If `terms` is specified, a member is created; + if `non_member_terms` is specified, a club rep is created. + requestBody: + content: + application/json: + schema: + type: object + properties: + uid: + $ref: "#/components/schemas/UID" + cn: + $ref: "#/components/schemas/UserCN" + program: + $ref: "#/components/schemas/Program" + terms: + $ref: "#/components/schemas/Terms" + non_member_terms: + $ref: "#/components/schemas/NonMemberTerms" + forwarding_addresses: + $ref: "#/components/schemas/ForwardingAddresses" + responses: + "200": + description: Success + content: + text/plain: + schema: + type: string + description: Streaming response + example: | + {"status": "in progress", "operation": "add_user_to_ldap"} + {"status": "in progress", "operation": "add_group_to_ldap"} + {"status": "in progress", "operation": "add_user_to_kerberos"} + {"status": "in progress", "operation": "create_home_dir"} + {"status": "in progress", "operation": "send_welcome_message"} + {"status": "in progress", "operation": "subscribe_to_mailing_list"} + {"status": "in progress", "operation": "announce_new_user"} + {"status": "completed", "result": {"cn": "Calum Dalek", "uid": "ctdalek", "uid_number": 20001, "gid_number": 20001, "login_shell": "/bin/bash", "home_directory": "/users/ctdalek", "is_club": false, "program": "MAT/Mathematics Computer Science", "terms": ["f2021"], "forwarding_addresses": ["ctdalek@uwaterloo.ca"], "password": "Wlw1wOTofERTEBlXWzR6/MZL"}} + /members/{username}: + get: + tags: ['members'] + summary: Get information about a user + description: >- + Returns information about a member or club rep. The `forwarding_addresses` field + will only be present if the client is an authenticated syscom member. + parameters: + - name: username + in: path + description: username of the user to return + required: true + schema: + type: string + responses: + "200": + description: Success + content: + application/json: + schema: + $ref: "#/components/schemas/User" + "404": + $ref: "#/components/responses/UserNotFoundErrorResponse" + patch: + tags: ['members'] + summary: Modify a user + description: Replace the login shell and/or forwarding addresses of a user + parameters: + - name: username + in: path + description: username of the user to modify + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + type: object + properties: + login_shell: + $ref: "#/components/schemas/LoginShell" + forwarding_addresses: + $ref: "#/components/schemas/ForwardingAddresses" + responses: + "200": + description: Success + content: + text/plain: + schema: + type: string + description: Streaming response + example: | + {"status": "in progress", "operation": "replace_login_shell"} + {"status": "in progress", "operation": "replace_forwarding_addresses"} + {"status": "completed", "result": "OK"} + "404": + $ref: "#/components/responses/UserNotFoundErrorResponse" + /members/{username}/renew: + post: + tags: ['members'] + summary: Renew a user + description: Add member **or** non-member terms to a user + parameters: + - name: username + in: path + description: username of the user to renew + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + oneOf: + - type: object + properties: + terms: + type: array + description: Terms for which this user will be a member + items: + $ref: "#/components/schemas/Term" + - type: object + properties: + non_member_terms: + type: array + description: Terms for which this user will be a club rep + items: + $ref: "#/components/schemas/Term" + example: {"terms": ["f2021"]} + responses: + "200": + description: Success + content: + application/json: + schema: + oneOf: + - type: object + properties: + terms_added: + type: array + description: Member terms which were added to this user + items: + $ref: "#/components/schemas/Term" + - type: object + properties: + non_member_terms_added: + type: array + description: Non-member terms which were added to this user + items: + $ref: "#/components/schemas/Term" + example: {"terms_added": ["f2021"]} + "404": + $ref: "#/components/responses/UserNotFoundErrorResponse" + /members/{username}/pwreset: + post: + tags: ['members'] + summary: Reset a user's password + description: >- + Sets a user's password to a randomly generated string, and returns it. The user will be + prompted to set a new password on their next login. + parameters: + - name: username + in: path + description: username of the user whose password will be reset + required: true + schema: + type: string + responses: + "200": + description: Success + content: + application/json: + schema: + type: object + properties: + password: + type: string + description: The user's new password + example: "EPGbJwLl1pmiWz8Wvu/MSs+v" + "404": + $ref: "#/components/responses/UserNotFoundErrorResponse" + /groups: + post: + tags: ['groups'] + summary: Create a new group + description: >- + Creates a new Unix group for a club. A new Unix user account with the same name will also be created. + A sudo role will be created allowing members of the group to become this user. + requestBody: + content: + application/json: + schema: + type: object + properties: + cn: + $ref: "#/components/schemas/GroupCN" + description: + $ref: "#/components/schemas/GroupDescription" + responses: + "200": + description: Success + content: + text/plain: + schema: + type: string + description: Streaming response + example: | + {"status": "in progress", "operation": "add_user_to_ldap"} + {"status": "in progress", "operation": "add_group_to_ldap"} + {"status": "in progress", "operation": "add_sudo_role"} + {"status": "in progress", "operation": "create_home_dir"} + {"status": "completed", "result": {"cn": "uwclub1", "gid_number": 30001, "description": "Club One", "members": []}} + /groups/{group_name}: + get: + tags: ['groups'] + summary: Get information about a group + description: Returns information about a group + security: [] + parameters: + - name: group_name + in: path + description: name of the group to return + required: true + schema: + type: string + responses: + "200": + description: Success + content: + application/json: + schema: + type: object + properties: + cn: + $ref: "#/components/schemas/GroupCN" + description: + $ref: "#/components/schemas/GroupDescription" + gid_number: + $ref: "#/components/schemas/GIDNumber" + members: + type: array + description: Members of the group + items: + $ref: "#/components/schemas/UID" + "404": + $ref: "#/components/responses/GroupNotFoundErrorResponse" + /groups/{group_name}/members/{username}: + post: + tags: ['groups'] + summary: Add a member to a group + description: >- + Adds a member to a group. The member will also be added to any auxiliary groups + specified in ceod.conf. The member may also be added to auxiliary mailing lists. + parameters: + - name: group_name + in: path + description: name of the group to which the member will be added + required: true + schema: + type: string + - name: username + in: path + description: username of the member who will be added to the group + required: true + schema: + type: string + - name: subscribe_to_lists + in: query + description: whether the member should be subscribed to auxiliary mailing lists + schema: + type: boolean + default: true + responses: + "200": + description: Success + content: + text/plain: + schema: + type: string + example: | + {"status": "in progress", "operation": "add_user_to_group"} + {"status": "in progress", "operation": "add_user_to_auxiliary_groups"} + {"status": "in progress", "operation": "subscribe_user_to_auxiliary_mailing_lists"} + {"status": "completed", "result": {"added_to_groups": ["group2","group3"], "subscribed_to_lists": ["list1","list2"]}} + "404": + $ref: "#/components/responses/GroupNotFoundErrorResponse" + delete: + tags: ['groups'] + summary: Remove a member from a group + description: >- + Removes a member from a group. The member will also be removed from any auxiliary groups + specified in ceod.conf. The member may also be removed from auxiliary mailing lists. + parameters: + - name: group_name + in: path + description: name of the group from which the member will be removed + required: true + schema: + type: string + - name: username + in: path + description: username of the member who will be removed from the group + required: true + schema: + type: string + - name: unsubscribe_from_lists + in: query + description: whether the member should be unsubscribed from auxiliary mailing lists + schema: + type: boolean + default: true + responses: + "200": + description: Success + content: + text/plain: + schema: + type: string + example: | + {"status": "in progress", "operation": "remove_user_from_group"} + {"status": "in progress", "operation": "remove_user_from_auxiliary_groups"} + {"status": "in progress", "operation": "unsubscribe_user_from_auxiliary_mailing_lists"} + {"status": "completed", "result": {"removed_from_groups": ["group2","group3"], "unsubscribed_from_lists": ["list1","list2"]}} + "404": + $ref: "#/components/responses/GroupNotFoundErrorResponse" + /positions: + get: + tags: ['positions'] + summary: Show current positions + description: >- + Shows the list of positions and members holding them. + responses: + "200": + description: Success + content: + application/json: + schema: + type: object + additionalProperties: + type: string + example: + president: user0 + vice-president: user1 + sysadmin: user2 + treasurer: + post: + tags: ['positions'] + summary: Update positions + description: >- + Update members for each positions. Members not specified in the parameters will be removed + from the position and unsubscribed from the exec's mailing list. New position holders will + be subscribed to the mailing list. + requestBody: + description: New position holders + required: true + content: + application/json: + schema: + type: object + additionalProperties: + type: string + example: + president: user0 + vice-president: user1 + sysadmin: user2 + treasurer: + responses: + "200": + description: Success + content: + text/plain: + schema: + type: string + description: Streaming response + example: | + {"status": "in progress", "operation": "update_positions_ldap"} + {"status": "in progress", "operation": "update_exec_group_ldap"} + {"status": "in progress", "operation": "subscribe_to_mailing_list"} + {"status": "completed", "result": "OK"} + "400": + description: Failed + content: + application/json: + schema: + type: object + properties: + error: + type: string + /mailman/{mailing_list}/{username}: + post: + tags: ['mailman'] + servers: + - url: "https://mail.csclub.uwaterloo.ca:9987/api" + summary: subscribe a user to a mailing list + description: Subscribes a user to a mailing list. + parameters: + - name: mailing_list + in: path + description: >- + The name of the list to which the user will be subscribed. If there is no '@' symbol, + then '@csclub.uwaterloo.ca' will be appended to the list name. + required: true + schema: + type: string + - name: username + in: path + required: true + description: >- + The user who will be subscribed to the list. If there is no '@' symbol, then '@csclub.uwaterloo.ca' + will be appended to he username; otherwise, the given email address will be subscribed. + schema: + type: string + responses: + "200": + description: Success + content: + application/json: + schema: + type: object + properties: + result: + type: string + example: OK + "404": + $ref: "#/components/responses/NoSuchListErrorResponse" + "409": + $ref: "#/components/responses/UserAlreadySubscribedErrorResponse" + delete: + tags: ['mailman'] + servers: + - url: "https://mail.csclub.uwaterloo.ca:9987/api" + summary: unsubscribe a user from a mailing list + description: Unsubscribes a user from a mailing list. + parameters: + - name: mailing_list + in: path + description: >- + The name of the list from which the user will be unsubscribed. If there is no '@' symbol, + then '@csclub.uwaterloo.ca' will be appended to the list name. + required: true + schema: + type: string + - name: username + in: path + required: true + description: >- + The user who will be unsubscribed from the list. If there is no '@' symbol, then '@csclub.uwaterloo.ca' + will be appended to he username; otherwise, the given email address will be unsubscribed. + schema: + type: string + responses: + "200": + description: Success + content: + application/json: + schema: + type: object + properties: + result: + type: string + example: OK + "404": + $ref: "#/components/responses/UserAlreadySubscribedOrNoSuchListErrorResponse" + /uwldap/{username}: + get: + tags: ['uwldap'] + security: [] + summary: get UWLDAP information for a user + description: Returns information about a user from the UW LDAP directory. + parameters: + - name: username + in: path + description: username of the user to return + required: true + schema: + type: string + responses: + "200": + description: Success + content: + application/json: + schema: + $ref: "#/components/schemas/UWLDAPUser" + "404": + $ref: "#/components/responses/UserNotFoundErrorResponse" + /uwldap/updateprograms: + post: + tags: ['uwldap'] + summary: update CSC programs from UWLDAP + description: | + Sync the 'program' attribute in the CSC LDAP with the UW LDAP. + The JSON request body may be omitted. + parameters: + - name: dry_run + in: query + description: >- + Whether to perform a dry run or not. If true, a list of members who *would* have been + changed is returned. + schema: + type: boolean + default: false + requestBody: + content: + application/json: + schema: + type: object + properties: + members: + type: array + description: If non-empty, only these members will be synced with UWLDAP + default: [] + items: + $ref: "#/components/schemas/UID" + responses: + "200": + description: Success + content: + application/json: + schema: + type: array + description: >- + A list of members whose programs were (or who would have been) changed. + Each item of the list is a 3-tuple of the form (username, old_program, new_program). + items: + type: array + items: + type: string + example: [['ctdalek', 'old_program', 'new_program']] + /db/mysql/{username}: + post: + tags: ['database'] + servers: + - url: https://caffeine.csclub.uwaterloo.ca:9987/api + summary: Create a MySQL database + description: Create a MySQL database for the user + parameters: + - name: username + in: path + description: name of the user to create MySQL database for + required: true + schema: + type: string + responses: + "200": + description: Success + content: + application/json: + schema: + type: object + properties: + password: + type: string + description: The password to the database + example: {"password": "7fUi5rQr/lcpeEj4M86ZBbwM"} + "400": + $ref: "#/components/responses/InvalidUsernameErrorResponse" + "404": + $ref: "#/components/responses/UserNotFoundErrorResponse" + "409": + $ref: "#/components/responses/DBAlreadyCreatedErrorResponse" + "500": + $ref: "#/components/responses/DBConnectionOrPermissionErrorResponse" + /db/mysql/{username}/pwreset: + post: + tags: ['database'] + servers: + - url: https://caffeine.csclub.uwaterloo.ca:9987/api + summary: Reset MySQL database password + description: Reset the password for a user's MySQL database + parameters: + - name: username + in: path + description: name of the user to reset the MySQL database password for + required: true + schema: + type: string + responses: + "200": + description: Success + content: + application/json: + schema: + type: object + properties: + password: + type: string + description: The new password to the database + example: {"password": "kM90d3G/eofIUxr9O3CQHTlP"} + "400": + $ref: "#/components/responses/InvalidUsernameErrorResponse" + "404": + $ref: "#/components/responses/UserNotFoundErrorResponse" + "500": + $ref: "#/components/responses/DBConnectionOrPermissionErrorResponse" + /db/postgresql/{username}: + post: + tags: ['database'] + servers: + - url: https://caffeine.csclub.uwaterloo.ca:9987/api + summary: Create a PostgreSQL database + description: Create a PostgreSQL database for the user + parameters: + - name: username + in: path + description: name of the user to create PostgreSQL database for + required: true + schema: + type: string + responses: + "200": + description: Success + content: + application/json: + schema: + type: object + properties: + password: + type: string + description: The password to the database + example: {"password": "iHxd62DC7Qt1HyYRj18P6ujS"} + "400": + $ref: "#/components/responses/InvalidUsernameErrorResponse" + "404": + $ref: "#/components/responses/UserNotFoundErrorResponse" + "409": + $ref: "#/components/responses/DBAlreadyCreatedErrorResponse" + "500": + $ref: "#/components/responses/DBConnectionOrPermissionErrorResponse" + /db/postgresql/{username}/pwreset: + post: + tags: ['database'] + servers: + - url: https://caffeine.csclub.uwaterloo.ca:9987/api + summary: Reset PostgreSQL database password + description: Reset the password for a user's PostgreSQL database + parameters: + - name: username + in: path + description: name of the user to reset the PostgreSQL database password for + required: true + schema: + type: string + responses: + "200": + description: Success + content: + application/json: + schema: + type: object + properties: + password: + type: string + description: The new password to the database + example: {"password": "CdPHT49iYAWzzKuhKTt2dNeu"} + "400": + $ref: "#/components/responses/InvalidUsernameErrorResponse" + "404": + $ref: "#/components/responses/UserNotFoundErrorResponse" + "500": + $ref: "#/components/responses/DBConnectionOrPermissionErrorResponse" +components: + securitySchemes: + GSSAPIAuth: + type: http + scheme: negotiate + description: | + ceod uses SPNEGO-based authentication over HTTP, as specified in [RFC 4559](https://datatracker.ietf.org/doc/html/rfc4559). + It is basically a base64-encoded Kerberos ticket wrapped in a HTTP header. For endpoints which make modifications + to LDAP, the Delegate flag must also be set. + + For example, with cURL: + ```sh + kinit + curl --negotiate -u : --service-name ceod --delegation always -X POST -d '{"terms":["w2022"]}' https://phosphoric-acid.csclub.uwaterloo.ca/api/members/ctdalek/renew + ``` + schemas: + UserCN: + type: string + description: Full name + example: Calum Dalek + UID: + type: string + description: Username + example: ctdalek + Program: + type: string + description: Academic program + example: MAT/Mathematics Computer Science + Terms: + type: array + description: Terms for which this user was a member + items: + $ref: "#/components/schemas/Term" + NonMemberTerms: + type: array + description: Terms for which this user was a club rep + items: + $ref: "#/components/schemas/Term" + LoginShell: + type: string + description: Login shell + example: /bin/bash + UIDNumber: + type: integer + description: UID number + example: 20001 + GIDNumber: + type: integer + description: GID number + example: 20001 + User: + type: object + properties: + cn: + $ref: "#/components/schemas/UserCN" + uid: + $ref: "#/components/schemas/UID" + uid_number: + $ref: "#/components/schemas/UIDNumber" + gid_number: + $ref: "#/components/schemas/GIDNumber" + home_directory: + type: string + description: Home directory + example: /users/ctdalek + is_club: + type: boolean + description: Whether this user is a club account or not + example: false + login_shell: + $ref: "#/components/schemas/LoginShell" + program: + $ref: "#/components/schemas/Program" + positions: + type: array + description: Positions held by this member + items: + type: string + example: president + terms: + $ref: "#/components/schemas/Terms" + non_member_terms: + $ref: "#/components/schemas/NonMemberTerms" + forwarding_addresses: + $ref: "#/components/schemas/ForwardingAddresses" + UWLDAPUser: + type: object + properties: + uid: + $ref: "#/components/schemas/UID" + cn: + $ref: "#/components/schemas/UserCN" + given_name: + type: string + description: Given name + example: Calum + sn: + type: string + description: Surname + example: Dalek + mail_local_addresses: + type: array + description: UW email addresses for this user + items: + type: string + format: email + example: ctdalek@uwaterloo.ca + ForwardingAddresses: + type: array + description: Forwarding addresses in ~/.forward + items: + type: string + format: email + example: ctdalek@uwaterloo.ca + Term: + type: string + description: Academic term + example: f2021 + GroupCN: + type: string + description: the name of the group + example: uwclub1 + GroupDescription: + type: string + description: a description of the group + example: Club One + responses: + ErrorResponse: &ErrorResponse + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Error message + UserNotFoundErrorResponse: + <<: *ErrorResponse + description: User not found + GroupNotFoundErrorResponse: + <<: *ErrorResponse + description: Group not found + UserAlreadySubscribedErrorResponse: + <<: *ErrorResponse + description: User is already subscribed + NoSuchListErrorResponse: + <<: *ErrorResponse + description: Mailing list does not exist + UserAlreadySubscribedOrNoSuchListErrorResponse: + <<: *ErrorResponse + description: User is already subscribed or mailing list does not exist + DBAlreadyCreatedErrorResponse: + <<: *ErrorResponse + description: User already has a database + InvalidUsernameErrorResponse: + <<: *ErrorResponse + description: Username contains invalid characters + DBConnectionOrPermissionErrorResponse: + <<: *ErrorResponse + description: Unable to connect to database or action failed due to permissions + diff --git a/docs/redoc-static.html b/docs/redoc-static.html new file mode 100644 index 0000000..00ee29e --- /dev/null +++ b/docs/redoc-static.html @@ -0,0 +1,608 @@ + + + + + + ceod - OpenAPI 3.0 + + + + + + + + + +

ceod - OpenAPI 3.0 (1.0.0)

Download OpenAPI specification:Download

This is an OpenAPI specification of ceod, the CSC Electronic Office daemon. +Visit the git repository for +more details.

+

Streaming Responses

Many endpoints return a "streaming response", which consists of a series of JSON +objects, one per line (the mimetype is text/plain). For example:

+
{"status": "in progress", "operation": "replace_login_shell"}
+{"status": "in progress", "operation": "replace_forwarding_addresses"}
+{"status": "completed", "result": "OK"}

Whenever an operation is completed, a corresponding JSON object will be streamed +from the server to the client. This allows the client to track the server's progress +in real time.

+

Authentication

GSSAPIAuth

ceod uses SPNEGO-based authentication over HTTP, as specified in RFC 4559. +It is basically a base64-encoded Kerberos ticket wrapped in a HTTP header. For endpoints which make modifications +to LDAP, the Delegate flag must also be set.

+

For example, with cURL:

+
kinit
+curl --negotiate -u : --service-name ceod --delegation always -X POST -d '{"terms":["w2022"]}' https://phosphoric-acid.csclub.uwaterloo.ca/api/members/ctdalek/renew
+
Security Scheme Type HTTP
HTTP Authorization Scheme negotiate

members

Operations on members and club reps

+

Create a new user

Creates a new member or club rep. If terms is specified, a member is created; if non_member_terms is specified, a club rep is created.

+
Authorizations:
Request Body schema: application/json
uid
string (UID)

Username

+
cn
string (UserCN)

Full name

+
program
string (Program)

Academic program

+
terms
Array of strings (Terms)

Terms for which this user was a member

+
non_member_terms
Array of strings (NonMemberTerms)

Terms for which this user was a club rep

+
forwarding_addresses
Array of strings <email> (ForwardingAddresses)

Forwarding addresses in ~/.forward

+

Responses

Request samples

Content type
application/json
{
  • "uid": "ctdalek",
  • "cn": "Calum Dalek",
  • "program": "MAT/Mathematics Computer Science",
  • "terms": [
    ],
  • "non_member_terms": [
    ],
  • "forwarding_addresses": [
    ]
}

Response samples

Content type
text/plain
{"status": "in progress", "operation": "add_user_to_ldap"}
+{"status": "in progress", "operation": "add_group_to_ldap"}
+{"status": "in progress", "operation": "add_user_to_kerberos"}
+{"status": "in progress", "operation": "create_home_dir"}
+{"status": "in progress", "operation": "send_welcome_message"}
+{"status": "in progress", "operation": "subscribe_to_mailing_list"}
+{"status": "in progress", "operation": "announce_new_user"}
+{"status": "completed", "result": {"cn": "Calum Dalek", "uid": "ctdalek", "uid_number": 20001, "gid_number": 20001, "login_shell": "/bin/bash", "home_directory": "/users/ctdalek", "is_club": false, "program": "MAT/Mathematics Computer Science", "terms": ["f2021"], "forwarding_addresses": ["ctdalek@uwaterloo.ca"], "password": "Wlw1wOTofERTEBlXWzR6/MZL"}}
+

Get information about a user

Returns information about a member or club rep. The forwarding_addresses field will only be present if the client is an authenticated syscom member.

+
Authorizations:
path Parameters
username
required
string

username of the user to return

+

Responses

Response samples

Content type
application/json
{
  • "cn": "Calum Dalek",
  • "uid": "ctdalek",
  • "uid_number": 20001,
  • "gid_number": 20001,
  • "home_directory": "/users/ctdalek",
  • "is_club": false,
  • "login_shell": "/bin/bash",
  • "program": "MAT/Mathematics Computer Science",
  • "positions": [
    ],
  • "terms": [
    ],
  • "non_member_terms": [
    ],
  • "forwarding_addresses": [
    ]
}

Modify a user

Replace the login shell and/or forwarding addresses of a user

+
Authorizations:
path Parameters
username
required
string

username of the user to modify

+
Request Body schema: application/json
login_shell
string (LoginShell)

Login shell

+
forwarding_addresses
Array of strings <email> (ForwardingAddresses)

Forwarding addresses in ~/.forward

+

Responses

Request samples

Content type
application/json
{
  • "login_shell": "/bin/bash",
  • "forwarding_addresses": [
    ]
}

Response samples

Content type
text/plain
{"status": "in progress", "operation": "replace_login_shell"}
+{"status": "in progress", "operation": "replace_forwarding_addresses"}
+{"status": "completed", "result": "OK"}
+

Renew a user

Add member or non-member terms to a user

+
Authorizations:
path Parameters
username
required
string

username of the user to renew

+
Request Body schema: application/json
One of
terms
Array of strings (Term)

Terms for which this user will be a member

+

Responses

Request samples

Content type
application/json
{
  • "terms": [
    ]
}

Response samples

Content type
application/json
{
  • "terms_added": [
    ]
}

Reset a user's password

Sets a user's password to a randomly generated string, and returns it. The user will be prompted to set a new password on their next login.

+
Authorizations:
path Parameters
username
required
string

username of the user whose password will be reset

+

Responses

Response samples

Content type
application/json
{
  • "password": "EPGbJwLl1pmiWz8Wvu/MSs+v"
}

groups

Operations on groups and clubs

+

Create a new group

Creates a new Unix group for a club. A new Unix user account with the same name will also be created. A sudo role will be created allowing members of the group to become this user.

+
Authorizations:
Request Body schema: application/json
cn
string (GroupCN)

the name of the group

+
description
string (GroupDescription)

a description of the group

+

Responses

Request samples

Content type
application/json
{
  • "cn": "uwclub1",
  • "description": "Club One"
}

Response samples

Content type
text/plain
{"status": "in progress", "operation": "add_user_to_ldap"}
+{"status": "in progress", "operation": "add_group_to_ldap"}
+{"status": "in progress", "operation": "add_sudo_role"}
+{"status": "in progress", "operation": "create_home_dir"}
+{"status": "completed", "result": {"cn": "uwclub1", "gid_number": 30001, "description": "Club One", "members": []}}
+

Get information about a group

Returns information about a group

+
path Parameters
group_name
required
string

name of the group to return

+

Responses

Response samples

Content type
application/json
{
  • "cn": "uwclub1",
  • "description": "Club One",
  • "gid_number": 20001,
  • "members": [
    ]
}

Add a member to a group

Adds a member to a group. The member will also be added to any auxiliary groups specified in ceod.conf. The member may also be added to auxiliary mailing lists.

+
Authorizations:
path Parameters
group_name
required
string

name of the group to which the member will be added

+
username
required
string

username of the member who will be added to the group

+
query Parameters
subscribe_to_lists
boolean
Default: true

whether the member should be subscribed to auxiliary mailing lists

+

Responses

Response samples

Content type
text/plain
{"status": "in progress", "operation": "add_user_to_group"}
+{"status": "in progress", "operation": "add_user_to_auxiliary_groups"}
+{"status": "in progress", "operation": "subscribe_user_to_auxiliary_mailing_lists"}
+{"status": "completed", "result": {"added_to_groups": ["group2","group3"], "subscribed_to_lists": ["list1","list2"]}}
+

Remove a member from a group

Removes a member from a group. The member will also be removed from any auxiliary groups specified in ceod.conf. The member may also be removed from auxiliary mailing lists.

+
Authorizations:
path Parameters
group_name
required
string

name of the group from which the member will be removed

+
username
required
string

username of the member who will be removed from the group

+
query Parameters
unsubscribe_from_lists
boolean
Default: true

whether the member should be unsubscribed from auxiliary mailing lists

+

Responses

Response samples

Content type
text/plain
{"status": "in progress", "operation": "remove_user_from_group"}
+{"status": "in progress", "operation": "remove_user_from_auxiliary_groups"}
+{"status": "in progress", "operation": "unsubscribe_user_from_auxiliary_mailing_lists"}
+{"status": "completed", "result": {"removed_from_groups": ["group2","group3"], "unsubscribed_from_lists": ["list1","list2"]}}
+

mailman

Operations on mailing list subscriptions

+

subscribe a user to a mailing list

Subscribes a user to a mailing list.

+
Authorizations:
path Parameters
mailing_list
required
string

The name of the list to which the user will be subscribed. If there is no '@' symbol, then '@csclub.uwaterloo.ca' will be appended to the list name.

+
username
required
string

The user who will be subscribed to the list. If there is no '@' symbol, then '@csclub.uwaterloo.ca' will be appended to he username; otherwise, the given email address will be subscribed.

+

Responses

Response samples

Content type
application/json
{
  • "result": "OK"
}

unsubscribe a user from a mailing list

Unsubscribes a user from a mailing list.

+
Authorizations:
path Parameters
mailing_list
required
string

The name of the list from which the user will be unsubscribed. If there is no '@' symbol, then '@csclub.uwaterloo.ca' will be appended to the list name.

+
username
required
string

The user who will be unsubscribed from the list. If there is no '@' symbol, then '@csclub.uwaterloo.ca' will be appended to he username; otherwise, the given email address will be unsubscribed.

+

Responses

Response samples

Content type
application/json
{
  • "result": "OK"
}

uwldap

Operations related to the UW LDAP directory

+

get UWLDAP information for a user

Returns information about a user from the UW LDAP directory.

+
path Parameters
username
required
string

username of the user to return

+

Responses

Response samples

Content type
application/json
{
  • "uid": "ctdalek",
  • "cn": "Calum Dalek",
  • "given_name": "Calum",
  • "sn": "Dalek",
  • "mail_local_addresses": [
    ]
}

update CSC programs from UWLDAP

Sync the 'program' attribute in the CSC LDAP with the UW LDAP. +The JSON request body may be omitted.

+
Authorizations:
query Parameters
dry_run
boolean
Default: false

Whether to perform a dry run or not. If true, a list of members who would have been changed is returned.

+
Request Body schema: application/json
members
Array of strings (UID)
Default: []

If non-empty, only these members will be synced with UWLDAP

+

Responses

Request samples

Content type
application/json
{
  • "members": [ ]
}

Response samples

Content type
application/json
[
  • [
    ]
]

database

Operations related to databases

+

Create a MySQL database

Create a MySQL database for the user

+
Authorizations:
path Parameters
username
required
string

name of the user to create MySQL database for

+

Responses

Response samples

Content type
application/json
{
  • "password": "7fUi5rQr/lcpeEj4M86ZBbwM"
}

Reset MySQL database password

Reset the password for a user's MySQL database

+
Authorizations:
path Parameters
username
required
string

name of the user to reset the MySQL database password for

+

Responses

Response samples

Content type
application/json
{
  • "password": "kM90d3G/eofIUxr9O3CQHTlP"
}

Create a PostgreSQL database

Create a PostgreSQL database for the user

+
Authorizations:
path Parameters
username
required
string

name of the user to create PostgreSQL database for

+

Responses

Response samples

Content type
application/json
{
  • "password": "iHxd62DC7Qt1HyYRj18P6ujS"
}

Reset PostgreSQL database password

Reset the password for a user's PostgreSQL database

+
Authorizations:
path Parameters
username
required
string

name of the user to reset the PostgreSQL database password for

+

Responses

Response samples

Content type
application/json
{
  • "password": "CdPHT49iYAWzzKuhKTt2dNeu"
}

positions

Show current positions

Shows the list of positions and members holding them.

+
Authorizations:

Responses

Response samples

Content type
application/json
{
  • "president": "user0",
  • "vice-president": "user1",
  • "sysadmin": "user2",
  • "treasurer": null
}

Update positions

Update members for each positions. Members not specified in the parameters will be removed from the position and unsubscribed from the exec's mailing list. New position holders will be subscribed to the mailing list.

+
Authorizations:
Request Body schema: application/json

New position holders

+
property name*
string

Responses

Request samples

Content type
application/json
{
  • "president": "user0",
  • "vice-president": "user1",
  • "sysadmin": "user2",
  • "treasurer": null
}

Response samples

Content type
text/plain
{"status": "in progress", "operation": "update_positions_ldap"}
+{"status": "in progress", "operation": "update_exec_group_ldap"}
+{"status": "in progress", "operation": "subscribe_to_mailing_list"}
+{"status": "completed", "result": "OK"}
+
+ + + + \ No newline at end of file