From e355a460ffed85d4b3424c71d9351238a4e0e600 Mon Sep 17 00:00:00 2001 From: "William G. Thompson, Jr" <wgthom@gmail.com> Date: Tue, 28 May 2019 21:00:43 -0400 Subject: [PATCH] initial docs import --- docs/201/201.1.rst | 174 ++++++++++++ docs/201/201.2.rst | 114 ++++++++ docs/201/201.3.rst | 148 +++++++++++ docs/201/201.4.rst | 127 +++++++++ docs/201/201.5.rst | 85 ++++++ ...01-3-4.pspng-epa.grouper-loader.properties | 10 + .../201/examples/201-3-5.attribute-filter.xml | 66 +++++ ...01-4-4.pspng-epe.grouper-loader.properties | 9 + .../201/examples/201-4-5.attribute-filter.xml | 66 +++++ docs/201/index.rst | 18 ++ docs/401/401.1.rst | 249 ++++++++++++++++++ docs/401/401.2.rst | 236 +++++++++++++++++ docs/401/401.3.rst | 224 ++++++++++++++++ docs/401/401.4-example-solution.rst | 26 ++ docs/401/401.4.rst | 67 +++++ docs/401/appendix.rst | 217 +++++++++++++++ .../examples/401.1.3-pspng-config.properties | 90 +++++++ .../examples/401.2.2-pspng-config.properties | 100 +++++++ docs/401/examples/401.2.3-general-authn.xml | 181 +++++++++++++ .../401/examples/401.2.3-mfa-authn-config.xml | 88 +++++++ docs/401/examples/401.2.4-athletics-dept.txt | 15 ++ docs/401/examples/401.2.5-banner-netids.txt | 5 + .../401.3.2-grouper-loader.properties | 118 +++++++++ .../401.3.2-grouper.client.properties | 112 ++++++++ docs/401/index.rst | 22 ++ docs/401/intro.rst | 18 ++ docs/Makefile | 19 ++ docs/conf.py | 182 +++++++++++++ docs/index.rst | 25 ++ docs/make.bat | 35 +++ 30 files changed, 2846 insertions(+) create mode 100644 docs/201/201.1.rst create mode 100644 docs/201/201.2.rst create mode 100644 docs/201/201.3.rst create mode 100644 docs/201/201.4.rst create mode 100644 docs/201/201.5.rst create mode 100644 docs/201/examples/201-3-4.pspng-epa.grouper-loader.properties create mode 100644 docs/201/examples/201-3-5.attribute-filter.xml create mode 100644 docs/201/examples/201-4-4.pspng-epe.grouper-loader.properties create mode 100644 docs/201/examples/201-4-5.attribute-filter.xml create mode 100644 docs/201/index.rst create mode 100644 docs/401/401.1.rst create mode 100644 docs/401/401.2.rst create mode 100644 docs/401/401.3.rst create mode 100644 docs/401/401.4-example-solution.rst create mode 100644 docs/401/401.4.rst create mode 100644 docs/401/appendix.rst create mode 100644 docs/401/examples/401.1.3-pspng-config.properties create mode 100644 docs/401/examples/401.2.2-pspng-config.properties create mode 100644 docs/401/examples/401.2.3-general-authn.xml create mode 100644 docs/401/examples/401.2.3-mfa-authn-config.xml create mode 100644 docs/401/examples/401.2.4-athletics-dept.txt create mode 100644 docs/401/examples/401.2.5-banner-netids.txt create mode 100644 docs/401/examples/401.3.2-grouper-loader.properties create mode 100644 docs/401/examples/401.3.2-grouper.client.properties create mode 100644 docs/401/index.rst create mode 100644 docs/401/intro.rst create mode 100644 docs/Makefile create mode 100644 docs/conf.py create mode 100644 docs/index.rst create mode 100644 docs/make.bat diff --git a/docs/201/201.1.rst b/docs/201/201.1.rst new file mode 100644 index 0000000..c51bb59 --- /dev/null +++ b/docs/201/201.1.rst @@ -0,0 +1,174 @@ +==================================== +GTE 201.1 Basis and Reference Groups +==================================== + +------------------- +Learning Objectives +------------------- + +* Create and manage reference and basis groups +* Understand the difference between reference groups and basis groups +* Implement lifecycle requirements for subject attributes + +-------------- +Lab Components +-------------- + +* Grouper +* `Grouper Deployment Guide`_ + +-------- +Overview +-------- + +Often the best source of data for building institutional meaningful cohorts is a +combination of arcane employee/payroll/student codes from multiple source systems. +To leverage the power of Grouper these groups should be brought in as raw **basis groups**. + +Basis groups are used by the IAM analyst to construct institutional meaningful +cohorts that are required for access policy. Access policy does not reference +basis groups directly, rather the basis groups are used to build up reference +groups. This indirection provides the IAM analyst the ability to adjust to +changing source systems and business practices while keeping reference groups +and access policy relatively stable. Basis groups are typically only visible to +the IAM analyst, and would not normally be reflected out to applications and +directories. + +Reference groups tend to be organized in particular folder locations for convenience +and ease of use, but what makes a group a reference group is not its name or folder +location, but rather its intended use, definition and scope, and data management +expectations. + +A **reference group** is a set of subjects that is largely intended to be used by +reference within access policy. Reference groups can be thought of as labels or +tags that identify institutional meaningful cohorts. In this way, they can also +be viewed as subject attributes from an ABAC perspective. Access policies often +require cohorts organized via institutional affiliation (faculty, staff, student), +a particular office or department (president's office, finance division, chaplain), +program (chemistry students), and even residence or class year. All of these are +good examples of reference groups. + +This module will focus on creating and using basis and reference groups related to +students. + +---------------- +Exercise 201.1.1 +---------------- + +*Create an all student reference group to be used in access policy and the all +students mailing list* + +Reference groups for student by class year already exist. These are being +used for class year mailing lists. Membership in these are updated +automatically by loader jobs: + +* `ref:student:class2019` +* `ref:student:class2020` +* `ref:student:class2021` +* `ref:student:class2022` + +#. Create a new reference group representing all students, `ref:student:students`. +#. Add the class year reference groups as direct members to `students`. How + many students are there? Filter by *indirect membership*. +#. You remember that recently graduated students have a grace period of 6 months + during which they retain full student access. Add `ref:student:class2018` to + `ref:student:students`, and set the membership end date to Dec. 31, 2018. How + many students are there now? + + .. note:: + + In this case, recently graduated students are still considered to be students + for the purpose of access control. If recent graduates only retained a few + services, it might make more sense to add these former students to individual + allow policies for the services in question. + +---------------- +Exercise 201.1.2 +---------------- + +*Other Students* + +You remember that not all students have class years assigned. This includes part-time +students, employees taking courses, and non-matriculated students. Fortunately data +about these students is available in the SIS and a basis group has already been created +for us. + +#. Add `basis:student:student_no_class_year` to `ref:student:students`. How many + students are there, now? + +---------------- +Exercise 201.1.3 +---------------- + +*Exchange Students* + +You campus participates in an exchange program with a sister school. Students +from the sister school can take classes at your institution, but never have +official records in your SIS. They do however, have a local NetID. Registration +is done directly with the registrar and the student's home institution maintains +the student records. + +#. Add `basis:student:exchange_students` to `ref:student:students`. How many + students are there now? + +---------------- +Exercise 201.1.4 +---------------- + +*Transfer Students* + +Students who transfer into your campus often need access to systems well ahead +of SIS data being fully updated. + +#. Create a new basis group, `basis:student:transfer_student`. +#. Add `transfer_student` to `students` with an expiration 60 days out. +#. Add the following accounts to `transfer_student`: + + * agrady901 + * alee467 + * ascott776 + +#. Check how many students there are, now. The number of students did not go up + by 3 as you might have expected. Why? One of the transfer students was + already a member of `students`. Trace the membership on each of the transfer + students to determine which accounts already had the `students` subject + attribute, and why. + +---------------- +Exercise 201.1.5 +---------------- + +*Change of Status* + +Students who leave for a variety of reasons are given a 32 day grace period +during which they retain student access. Basis groups for these already exist. +They include: + +* `basis:student:expelled_32_days` +* `basis:student:resigned_32_days` +* `basis_student_transferred_32_days` + +#. Add these basis groups to `students`. How many students are there, now? + +---------------- +Exercise 201.1.6 +---------------- + +*Leave of Absence Students* + +Student may also obtain a leave of absence for a variety of reasons. These +students may or may not return, but retain student access for an extend period +of time. Basis groups for leave of absence students already exists: + +* `basis:student:loa_4_years` (leave of absence within the last 4 years) + +#. Add `loa_4_years` to `students`. How many students are there, now? + + + + + + + + +.. _Grouper Deployment Guide: https://spaces.at.internet2.edu/display/Grouper/Grouper+Deployment+Guide+Work+-TIER+Program diff --git a/docs/201/201.2.rst b/docs/201/201.2.rst new file mode 100644 index 0000000..8e9e125 --- /dev/null +++ b/docs/201/201.2.rst @@ -0,0 +1,114 @@ + +============================== +GTE 201.2 Access Policy Groups +============================== + +------------------- +Learning Objectives +------------------- + +* Translate a natural language policy group into digital policy using access policy groups. +* Understand the difference between policy groups and reference groups. + +-------------- +Lab Components +-------------- + +* Grouper +* `Grouper Deployment Guide`_ + +-------- +Overview +-------- + +`NIST SP 800-162`_ describes how natural language policy, that is access policy +stated in common language, must be converted to digital policy for any access +control mechanism to effectively operate. Digital policy is manifest in +Grouper via access policy groups. Subject membership in an access policy group +be indirect and represents a precomputed access policy decision based on subject +attributes (i.e. the subject’s membership in various reference groups). + +An **access policy** group is a composite group whose membership is composed of +an include group (i.e. the allow group) minus an exclude group (i.e. the deny +group). Subject membership in both the allow group and the deny group should be +indirect (i.e. through reference groups) and have a clear mapping to the natural +language policy. When exceptions to policy are necessary, locally scoped +reference groups should be added. + +Limiting policy groups to indirect membership assignments via reference groups +ensures that as subject attributes change, effective membership is up to date and +access control decisions are correct. It also enables the direct mapping from +natural language policy to digital policy and vice versa. Individual exceptions to +policy, while not expressly recommended, can be accommodated by adding subjects +directly to the allow/deny groups. + +Membership within an access policy group is often kept in sync directly with a target +service or an intermediary like an LDAP based enterprise directory service. +Services can also query Grouper directly for membership assignment. + +---------------- +Exercise 201.2.1 +---------------- + +*Application folder structure* + +#. Create `app:vpn:vpn_authorized`. +#. Create `app:vpn:vpn_allow`. +#. Create `app:vpn:vpn_deny`. +#. Make `vpn_authorized` a composite of `vpn_allow` minus `vpn_deny`. + +---------------- +Exercise 201.2.2 +---------------- + +*Create digital policy from natural language policy* + +Natural language policy is "all faculty, staff have access to vpn, unless denied +by CISO or the account is in a closure state". Reference groups are already +available. + +#. Add `ref:employee:fac_staff` to `vpn_allow`. +#. Add `ref:security:locked_by_ciso` to `vpn_deny`. +#. Add `ref:iam:closure` to `vpn_deny`. + +---------------- +Exercise 201.2.3 +---------------- + +*Update policy to also allow institutional review board members access to VPN* + +New natural language policy is "all faculty, staff and members of the institutional +review board have access to vpn, unless denied by CISO or the account is in a closure +state". + +#. Add `org:irb:ref:irb_members` to `vpn_allow`. +#. Add *jsmith* to `org:irb:ref:irb_members`. +#. Trace membership for *jsmith* from `vpn_authorized`. +#. View the audit log on `vpn_allow`. + +---------------- +Exercise 201.2.4 +---------------- + +*Create security groups for policy* + +#. Create `ref:app:vpn:etc` folder. +#. Create `ref:app:vpn:etc:vpn_admins` group. +#. Assign **ADMIN** privilege to `vpn_admins` for `ref:app:vpn`. +#. Inherit privileges to all sub folders (and objects). + + #. Navigate to `app:vpn`. + #. :guilabel:`More` |rightarrow| :guilabel:`Privileges inherited to objects in folder` + #. Click :guilabel:`Add Members`, and add `vpn_admins`. + #. Add admin privileges for folder, group, and attributes. + +#. Navigate to `ref:app:vpn:ref:vpn_allow`. +#. Click :guilabel:`Privileges` |rightarrow| :guilabel:`Actions` |rightarrow| :guilabel:`Trace Priviliges`. + + + +.. |rightarrow| unicode:: U+2192 + +.. _NIST SP 800-162: https://csrc.nist.gov/publications/detail/sp/800-162/final +.. _Grouper Deployment Guide: https://spaces.at.internet2.edu/display/Grouper/Grouper+Deployment+Guide+Work+-TIER+Program + diff --git a/docs/201/201.3.rst b/docs/201/201.3.rst new file mode 100644 index 0000000..9d861aa --- /dev/null +++ b/docs/201/201.3.rst @@ -0,0 +1,148 @@ + +=================================== +GTE 201.3 ACM1 eduPersonAffiliation +=================================== + +------------------- +Learning Objectives +------------------- + +* Understand ACM1 and how to implement subject attribute management with policy + groups +* Configure PSPNG to reflect group membership (aka subject attributes) into + OpenLDAP +* Configure Shibboleth to release **eduPersonAffiliation** + + +-------------- +Lab Components +-------------- + +* Grouper +* PSPNG +* OpenLDAP +* Shibboleth + +-------- +Overview +-------- + +`Grouper Deployment Guide`_ access control model 1 is all about subject attribute +management. This model is useful for cases where there exists a loose relationship +between the institution and the service provider. Assuming both are in a +federation like InCommon, and a locally defined notion of eduPersonAffiliation_ is +sufficient for access control, a broad set of services can be enabled fairly easily. + +.. warning:: + + This access control model is based on making subject attributes directly + available to services and allowing the service to make access control decisions + based on those attributes. This approach has several shortcomings: + + * The subject attributes provided often lack sufficient **context** to make + informed access control decisions. + * Managing changes to policy is difficult. + * Policy decisions become opaque. + + Consider a hypothetical Learning Management System (LMS) that consumes + **eduPersonAffiliation** attributes from subjects and grants access to a course + management module based on whether an account has the *faculty* affiliation + present. At first glance, this seems like a reasonable decision. However: + + * There are faculty who do not teach courses, and should probably not have + access to this module (*lack of context*). + * There are non-faculty instructors who teach courses who do need access to + this module (*lack of context*). + * Correcting either of the above issues is non-trivial. Updating instructor + accounts to assert the *faculty* affiliation may be permissible for the LMS, + but what impact will it have on other services that employ ACM1? Removing + the *faculty* affiliation from faculty who don't teach courses is even more + likely to cause issues (*managing changes to policy is difficult*). + * Exceptions may be negotiated by configuring the IdP to release different + affiliations based on the service provider requesting authentication (*policy + decisions become opaque*). + * Alternatively, exceptions may be handled by configuring them directly at + the service provider (*policy decisions become opaque*). + +---------------- +Exercise 201.3.1 +---------------- + +*Create app folder to master eduPersonAffiliation* + +#. Create folder `app:eduPersonAffiliation`. +#. Create groups `...:eduPersonAffiliation:ePA_student|staff|...` to represent + eduPersonAffiliation values. + +---------------- +Exercise 201.3.2 +---------------- + +*Add reference groups that constitute local policy for eduPersonAffiliation values* + + Therefore each institution will decide the criteria for membership in each + affiliation classification. What is desirable is that a reasonable person + should find an institution's definition of the affiliation plausible. + +#. Add `ref:student:students` to `...:eduPersonAffiliation:ePA_student`. + +---------------- +Exercise 201.3.3 +---------------- + +*Create "member"* + +The "member" affiliation MUST be asserted for people carrying one or more of +the following affiliations: *faculty* or *staff* or *student* or *employee*. + +.. note: + + Holders of the affiliation *alum* are not typically "members" since they + are not eligible for the full set of institutional privileges enjoyed by + faculty, staff and students. + +#. Create `app:eduPersonAffiliation:ePA_member`. +#. Add `...:ePA_faculty|staff|student|employee` to `...:ePA_member`. + +---------------- +Exercise 201.3.4 +---------------- + +*Configure PSPNG to reflect ePA values to LDAP* + +#. Assign PSPNG *provision_to* attribute to `ePA_student` with a value of + **pspng_affiliations**. +#. Configure PSPNG to sync group membership to LDAP values for + **eduPersonAffiliation**. + + .. literalinclude:: examples/201-3-4.pspng-epa.grouper-loader.properties + :language: properties + :caption: grouper-loader.properties + :linenos: + +---------------- +Exercise 201.3.5 +---------------- + +*Releasing ePA in SAML* + +The demo shibboleth IdP has been configured to release the ePA attribute to +the demo SP. The relevant configuration is below: + +.. literalinclude:: examples/201-3-5.attribute-filter.xml + :language: xml + :caption: attribute-filter.xml + :lines: 16-42 + :emphasize-lines: 9 + :linenos: + + + + + + + + + +.. _eduPersonAffiliation: https://www.internet2.edu/media/medialibrary/2013/09/04/internet2-mace-dir-eduperson-201203.html#eduPersonAffiliation +.. _Grouper Deployment Guide: https://spaces.at.internet2.edu/display/Grouper/Grouper+Deployment+Guide+Work+-TIER+Program diff --git a/docs/201/201.4.rst b/docs/201/201.4.rst new file mode 100644 index 0000000..2b96bac --- /dev/null +++ b/docs/201/201.4.rst @@ -0,0 +1,127 @@ + +=================================== +GTE 201.4 ACM2 eduPersonEntitlement +=================================== + +------------------- +Learning Objectives +------------------- + +* Understand ACM2 model and how to implement attribute based access control +* Implement grouper security model +* Configure PSPNG to convert membership to **eduPersonEntitlement** values in LDAP +* Configure Shibboleth to release specific **eduPersonEntitlement** values to SP + + +-------------- +Lab Components +-------------- + +* Grouper +* OpenLDAP +* Shibboleth +* `Grouper Deployment Guide`_ +* `eduPerson Object Class Specification`_ + + +-------- +Overview +-------- + +`Grouper Deployment Guide`_ access control model 2 is all about subject attribute +based access control. ACM2 is applicable across a broad range of services where +access control policy can be based on subject attributes, the policy decision can +be precomputed, and simple subject attributes are sufficient to drive the enforcement +point. + +"""" +ACM2 +"""" + +Implementing ACM2 can be distilled to these basic steps: + +#. Convert natural language policy to reference groups and policy groups +#. Provisioning to LDAP-- Grouper group |rightarrow| LDAP attribute via PSPNG +#. Release **eduPersonEntitlement** value in SAML authentication response + + +---------------- +Exercise 201.4.1 +---------------- + +*Create policy for wiki application* + +#. Create folder `app:wiki`. +#. Create policy groups `app:wiki:service:policy:wiki_authorized|allow|deny`. +#. Edit composite `wiki_authorized` to make it `wiki_allow` minus `wiki_deny`. + +---------------- +Exercise 201.4.2 +---------------- + +*Create security group* + +#. Create folder `app:wiki:security`. +#. Create security group `app:wiki:security:wiki_admin`. +#. Add **ADMIN** privileges to `wiki_admin` for `app:wiki:service`, and inherit + to all child objects (folders, groups, and attributes). + +---------------- +Exercise 201.4.3 +---------------- + +*Add reference groups to policy* + +#. Add `ref:student:students` to `app:wiki:service:policy:wiki_allow`. +#. Add `ref:iam:global_deny` to `app:wiki:service:policy:wiki_deny`. + +---------------- +Exercise 201.4.4 +---------------- + +*Configure PSPNG to reflect policy to eduPersonEntitlement in LDAP* + +#. Assign PSPNG attribute, **provision_to** to `wiki_authorized` with a value + of *pspng_entitlements*. +#. Configure PSPNG to convert membership to ePE value of http://sp.example.org/wiki + and review in LDAP. The relevent configuration is below: + + .. literalinclude:: examples/201-4-4.pspng-epe.grouper-loader.properties + :language: properties + :caption: grouper-loader.properties + :linenos: + +---------------- +Exercise 201.4.5 +---------------- + +*Configure Shib to release ePE value for our SP* + +The demo shibboleth IdP has been configured to release the ePE attribute to +the demo SP. The relevant configuration is below: + +.. literalinclude:: examples/201-4-5.attribute-filter.xml + :language: xml + :caption: attribute-filter.xml + :lines: 16-42 + :emphasize-lines: 17 + :linenos: + +---------------- +Exercise 201.4.6 +---------------- + +*(Thought exercise!) Create accounts at target SP* + +Use policy groups to create/manage accounts at target SP. + +* Native grouper SP specific provisioning components +* RabbitMQ based provisioning / deprovisioning +* midPoint + + + +.. |rightarrow| unicode:: U+2192 + +.. _eduPerson Object Class Specification: http://software.internet2.edu/eduperson/internet2-mace-dir-eduperson-201602.html +.. _Grouper Deployment Guide: https://spaces.at.internet2.edu/display/Grouper/Grouper+Deployment+Guide+Work+-TIER+Program diff --git a/docs/201/201.5.rst b/docs/201/201.5.rst new file mode 100644 index 0000000..d228427 --- /dev/null +++ b/docs/201/201.5.rst @@ -0,0 +1,85 @@ + +====================================== +GTE 201.5 ACM3 Subject to Role Mapping +====================================== + +------------------- +Learning Objectives +------------------- + +* Understand ACM3 and how to use grouper policy groups with application specific roles +* Implement delegated access control +* Configure attestation + +-------------- +Lab Components +-------------- + +* Grouper +* `Grouper Deployment Guide`_ + +-------- +Overview +-------- + +In applications with sophisticated RBAC capabilities, fine-grained permission +sets are typically configured via an administrative interface within the +application itself. These permission sets are then associated with a role name +that can be mapped to a set of users. In this model, the user to role mapping +is done in Grouper by pairing a normal access control group with the role name +defined at the target service. The policy indicating which subjects are mapped +to application roles (permissions sets) can be attribute based or a simple +access control list, or some combination of both. + +ACM3 is implemented using Grouper as follows: + +* Subject |rightarrow| Role assignment is made in Grouper. Access control policies are used to represent Roles. +* Fine-grained permission sets are managed at the target service and assigned a Role Name +* Grouper access control groups are mapped to target service Role Name, completing the User |rightarrow| Role mapping +* PAP split between Grouper and target service, PDP and PEP at service + +---------------- +Exercise 201.5.1 +---------------- + +*Create application folder and group set* + +Use wizard template (or gsh script) to create new application folder/group set. + +#. Create `app:cognos:service:security:cg_adv_manager`. +#. Create `app:cognos:service:ref` folder. +#. Create `app:cognos:service:policy` folder. +#. Create `app:congos:service:policy:cg_adv_report_reader|allow|deny`. +#. Create `app:congos:service:policy:cg_adv_report_writer|allow|deny`. + +---------------- +Exercise 201.5.2 +---------------- + +*Add reference groups to policy* + +#. Add `ref:dept:advancement` to `cg_adv_report_reader_allow`. + +---------------- +Exercise 201.5.3 +---------------- + +*Create app specific reference group for advancement report writers* + +#. Create `app:congos:service:ref:advancement_report_writer`. +#. Add `...:ref:advancement_report_writers` to `...:cg_adv_report_writer_allow`. +#. Add read/update privileges to `cg_adv_manager` to `cg_adv_report_writer_allow`. + +---------------- +Exercise 201.5.4 +---------------- + +*Add attestation* + +#. Add attestation requirement for `advancement_report_writer`. + + + +.. |rightarrow| unicode:: U+2192 + +.. _Grouper Deployment Guide: https://spaces.at.internet2.edu/display/Grouper/Grouper+Deployment+Guide+Work+-TIER+Program diff --git a/docs/201/examples/201-3-4.pspng-epa.grouper-loader.properties b/docs/201/examples/201-3-4.pspng-epa.grouper-loader.properties new file mode 100644 index 0000000..94f4438 --- /dev/null +++ b/docs/201/examples/201-3-4.pspng-epa.grouper-loader.properties @@ -0,0 +1,10 @@ +changeLog.consumer.pspng_affiliations.class = edu.internet2.middleware.grouper.pspng.PspChangelogConsumerShim +changeLog.consumer.pspng_affiliations.type = edu.internet2.middleware.grouper.pspng.LdapAttributeProvisioner +changeLog.consumer.pspng_affiliations.quartzCron = 0 * * * * ? +changeLog.consumer.pspng_affiliations.ldapPoolName = demo +changeLog.consumer.pspng_affiliations.provisionedAttributeName = eduPersonAffiliation +changeLog.consumer.pspng_affiliations.provisionedAttributeValueFormat = ${group.extension.replace('ePA_', '')} +changeLog.consumer.pspng_affiliations.userSearchBaseDn = ou=people,dc=internet2,dc=edu +changeLog.consumer.pspng_affiliations.userSearchFilter = uid=${subject.id} +changeLog.consumer.pspng_affiliations.allProvisionedValuesPrefix=* + diff --git a/docs/201/examples/201-3-5.attribute-filter.xml b/docs/201/examples/201-3-5.attribute-filter.xml new file mode 100644 index 0000000..0867564 --- /dev/null +++ b/docs/201/examples/201-3-5.attribute-filter.xml @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + This file is an EXAMPLE policy file. While the policy presented in this + example file is illustrative of some simple cases, it relies on the names of + non-existent example services and the example attributes demonstrated in the + default attribute-resolver.xml file. + + Deployers should refer to the documentation for a complete list of components + and their options. +--> +<AttributeFilterPolicyGroup id="ShibbolethFilterPolicy" + xmlns="urn:mace:shibboleth:2.0:afp" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="urn:mace:shibboleth:2.0:afp http://shibboleth.net/schema/idp/shibboleth-afp.xsd"> + + <!-- Release some attributes to an SP. --> + <AttributeFilterPolicy id="example1"> + <PolicyRequirementRule xsi:type="Requester" value="https://grouperdemo/shibboleth" /> + + <AttributeRule attributeID="cn"> + <PermitValueRule xsi:type="ANY" /> + </AttributeRule> + + <AttributeRule attributeID="eduPersonAffiliation"> + <PermitValueRule xsi:type="ANY" /> + </AttributeRule> + + <AttributeRule attributeID="eduPersonPrimaryAffiliation"> + <PermitValueRule xsi:type="ANY" /> + </AttributeRule> + + <AttributeRule attributeID="eduPersonEntitlement"> + <PermitValueRule xsi:type="ANY" /> + </AttributeRule> + + <AttributeRule attributeID="eduPersonPrincipalName"> + <PermitValueRule xsi:type="ANY" /> + </AttributeRule> + + <AttributeRule attributeID="eduPersonScopedAffiliation"> + <PermitValueRule xsi:type="ANY" /> + </AttributeRule> + + <AttributeRule attributeID="employeeNumber"> + <PermitValueRule xsi:type="ANY" /> + </AttributeRule> + + <AttributeRule attributeID="givenName"> + <PermitValueRule xsi:type="ANY" /> + </AttributeRule> + + <AttributeRule attributeID="mail"> + <PermitValueRule xsi:type="ANY" /> + </AttributeRule> + + <AttributeRule attributeID="surname"> + <PermitValueRule xsi:type="ANY" /> + </AttributeRule> + + <AttributeRule attributeID="uid"> + <PermitValueRule xsi:type="ANY" /> + </AttributeRule> + + </AttributeFilterPolicy> +</AttributeFilterPolicyGroup> + diff --git a/docs/201/examples/201-4-4.pspng-epe.grouper-loader.properties b/docs/201/examples/201-4-4.pspng-epe.grouper-loader.properties new file mode 100644 index 0000000..7c5ef95 --- /dev/null +++ b/docs/201/examples/201-4-4.pspng-epe.grouper-loader.properties @@ -0,0 +1,9 @@ +changeLog.consumer.pspng_entitlements.class = edu.internet2.middleware.grouper.pspng.PspChangelogConsumerShim +changeLog.consumer.pspng_entitlements.type = edu.internet2.middleware.grouper.pspng.LdapAttributeProvisioner +changeLog.consumer.pspng_entitlements.quartzCron = 0 * * * * ? +changeLog.consumer.pspng_entitlements.ldapPoolName = demo +changeLog.consumer.pspng_entitlements.provisionedAttributeName = eduPersonEntitlement +changeLog.consumer.pspng_entitlements.provisionedAttributeValueFormat = ${group.name.equalsIgnoreCase('app:wiki:service:policy:wiki_authorized') ? 'http://sp.example.org/wiki' : 'urn:mace:example.edu:' + group.extension} +changeLog.consumer.pspng_entitlements.userSearchBaseDn = ou=people,dc=internet2,dc=edu +changeLog.consumer.pspng_entitlements.userSearchFilter = uid=${subject.id} +changeLog.consumer.pspng_entitlements.allProvisionedValuesPrefix=* diff --git a/docs/201/examples/201-4-5.attribute-filter.xml b/docs/201/examples/201-4-5.attribute-filter.xml new file mode 100644 index 0000000..0867564 --- /dev/null +++ b/docs/201/examples/201-4-5.attribute-filter.xml @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + This file is an EXAMPLE policy file. While the policy presented in this + example file is illustrative of some simple cases, it relies on the names of + non-existent example services and the example attributes demonstrated in the + default attribute-resolver.xml file. + + Deployers should refer to the documentation for a complete list of components + and their options. +--> +<AttributeFilterPolicyGroup id="ShibbolethFilterPolicy" + xmlns="urn:mace:shibboleth:2.0:afp" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="urn:mace:shibboleth:2.0:afp http://shibboleth.net/schema/idp/shibboleth-afp.xsd"> + + <!-- Release some attributes to an SP. --> + <AttributeFilterPolicy id="example1"> + <PolicyRequirementRule xsi:type="Requester" value="https://grouperdemo/shibboleth" /> + + <AttributeRule attributeID="cn"> + <PermitValueRule xsi:type="ANY" /> + </AttributeRule> + + <AttributeRule attributeID="eduPersonAffiliation"> + <PermitValueRule xsi:type="ANY" /> + </AttributeRule> + + <AttributeRule attributeID="eduPersonPrimaryAffiliation"> + <PermitValueRule xsi:type="ANY" /> + </AttributeRule> + + <AttributeRule attributeID="eduPersonEntitlement"> + <PermitValueRule xsi:type="ANY" /> + </AttributeRule> + + <AttributeRule attributeID="eduPersonPrincipalName"> + <PermitValueRule xsi:type="ANY" /> + </AttributeRule> + + <AttributeRule attributeID="eduPersonScopedAffiliation"> + <PermitValueRule xsi:type="ANY" /> + </AttributeRule> + + <AttributeRule attributeID="employeeNumber"> + <PermitValueRule xsi:type="ANY" /> + </AttributeRule> + + <AttributeRule attributeID="givenName"> + <PermitValueRule xsi:type="ANY" /> + </AttributeRule> + + <AttributeRule attributeID="mail"> + <PermitValueRule xsi:type="ANY" /> + </AttributeRule> + + <AttributeRule attributeID="surname"> + <PermitValueRule xsi:type="ANY" /> + </AttributeRule> + + <AttributeRule attributeID="uid"> + <PermitValueRule xsi:type="ANY" /> + </AttributeRule> + + </AttributeFilterPolicy> +</AttributeFilterPolicyGroup> + diff --git a/docs/201/index.rst b/docs/201/index.rst new file mode 100644 index 0000000..dab143a --- /dev/null +++ b/docs/201/index.rst @@ -0,0 +1,18 @@ +Grouper Access Governance (201) +=============================== + +This course explores access governance approach described in the `Grouper +Deployment Guide`_. After completing this course, the student will understand +how to use Grouper primitives to achieve access governance capabilities, and be +able to translate natural language policy into digital policy. + +.. toctree:: + :maxdepth: 2 + + 201.1 + 201.2 + 201.3 + 201.4 + 201.5 + +.. _Grouper Deployment Guide: https://spaces.at.internet2.edu/display/Grouper/Grouper+Deployment+Guide+Work+-TIER+Program \ No newline at end of file diff --git a/docs/401/401.1.rst b/docs/401/401.1.rst new file mode 100644 index 0000000..9e78cfd --- /dev/null +++ b/docs/401/401.1.rst @@ -0,0 +1,249 @@ +======================== +401.1 VPN Access Control +======================== + +------------------- +Learning Objectives +------------------- + +* Use group math and reference groups to analyze legacy authorization groups +* Translate natural language policy into Grouper digital policy +* Implement distributed access management +* Use Grouper to answer access management questions such as "who" and "why" + +-------------- +Lab Components +-------------- + +* Grouper +* PSPNG +* OpenLDAP +* `Grouper Deployment Guide <https://spaces.at.internet2.edu/display/Grouper/Grouper+Deployment+Guide+Work+-TIER+Program>`_ + +-------- +Overview +-------- + +VPN access is currently controlled by an LDAP group. You are not exactly sure +who is in the group or what the policy is, but have a general notion of a +natural language policy as all active faculty and staff, plus exceptions. +However, people have been added to the VPN ldap group mostly by hand over many +years with little to no lifecycle management in place. There is no easy way to +determine who should or should not be in the group. We just had a major breach +which was facilitated by access to the VPN. The compromised account used in the +breach was given to a former consultant and was never deprovisioned. CISO is +coming down hard on us to clean up our act! + +---------------- +Exercise 401.1.1 +---------------- + +*Gain insight into who exactly has access to the VPN based on the cohorts found +in the legacy VPN authorization group.* + +"""""""""""""""""""""" +Import Legacy VPN Data +"""""""""""""""""""""" + +* Create a loader job from the existing ldap vpn authorization group. +* Make sure grouper group counts matches ldap group counts. +* First thing to notice is you can eyeball the types of subjects in Grouper UI. + +.. note:: + For small enough groups this might be sufficient, but our VPN group has + hundreds of subjects. + +""""""""""""""""""""""""""""""" +Use Set Operations for Analysis +""""""""""""""""""""""""""""""" + +Use intersect composite groups to gain insight into types of cohorts + +* `test:vpn:vpn_faculty`: Intersect `ref:faculty` with `test:vpn:vpn_legacy`. + This yields faculty count (almost) - aha! This explains help desk calls! + +* `test:vpn:vpn_employees`: Intersect `ref:staff` with `test:vpn:vpn_legacy`. + This yields staff count (again almost!) + +* `test:vpn:vpn_students`: Intersect `ref:students` with `test:vpn:vpn_legacy`. + This yields a small count - aha! + +* Totals don’t add up...so we have other cohorts too. Who are they? + +* Set up composite group to filter out "other cohorts". + +* `test:vpn:other_cohorts` = `...:vpn_legacy` - (`...:vpn_faculty` + + `...:vpn_employees` + `...:vpn_students`) + + * create `...:vpn_facstaffstudent` (include `...:vpn_faculty`, + `...:vpn_employees`, `...:vpn_students`) + * `...:other_cohorts` = `...:vpn_legacy` - `...:vpn_facstaffstudent` + +* "Other cohorts" is a relatively small number ... can now eyeball those. + + * fac/staff that are now longer active + * Contractors, sponsored accounts, etc + * Others + +---------------- +Exercise 401.1.2 +---------------- + +*State the natural language policy and create VPN application group and digital +policy.* + +#. Natural language policy: "Faculty, staff and exceptions (some students, + contractors, etc.)" +#. Construct `app:vpn:vpn_authorized|allow|deny` policy groups from appropriate + reference groups. + + * `ref:faculty` + * `ref:employees` + * `app:vpn:ref:vpn_adhoc` + +#. Compare counts between ldap vpn group and `app:vpn:vpn_authorized`. + `vpn_authorized` should be different from the legacy group in the following + ways: + + * only active accounts + * only current exceptions (none!) + +---------------- +Exercise 401.1.3 +---------------- + +*Export `vpn_authorized` to LDAP for use with new VPN config.* + +#. Mark/config `vpn_authorized` to export to LDAP. The PSPNG needs to be + configured to provision group members. + + .. literalinclude:: examples/401.1.3-pspng-config.properties + :language: properties + :lines: 72- + :caption: grouper-loader.properties + :name: 401.1.3-pspng-groupofnames + :linenos: + +#. Open a ticket to switch VPN config to use vpn_authorized. +#. Bask in the glow of TIER IAM goodness... + + * Automatic provisioning/deprovisioning for faculty and staff. + * Natural language policy - clear and visible. + * Exceptions management: + + * Still dealing with tickets to add and remove subjects (well at least to add!). + * No way to distinguish different exceptions. + * Who is responsible for lifecycle, attestation, etc.? + +---------------- +Exercise 401.1.4 +---------------- + +*Implement distributed exception management.* + +We initially added exceptions to single application reference group. This a +good step, but we still lack an easy way to know the "who and why" of +exceptions. IAM still also getting tickets to add people. In some case, the +expiration is known and added, but most are a one way street-- back to old +practices. How can we do better? + +""""""""""""""""""""""""""""" +Organize Exceptions to Policy +""""""""""""""""""""""""""""" + +Each policy exception is represented by an application specific reference group. + +#. Create `app:vpn:ref:vpn_consultants`. This ACL will be managed by the IAM + team. +#. Create `app:vpn:ref:vpn_ajohnson409`. Management of this ACL will be + delegated to a professor. + ++++++++++++++++++++++++++++++++++++ +Professor Johnson's Special Project ++++++++++++++++++++++++++++++++++++ + +Professor Johnson (**ajohnson409**) runs a special project that includes various online +resources that can only be accessed from the VPN. The professor should be able to +control who is allowed to have VPN access for the purpose of accessing his +project's resources. + +ACL `app:vpn:ref:vpn_ajohnson409` represents subjects that will access resources +related to Professor Johnson's special project. In order to delegate management +of this ACL to the professor, we must create a security group and grant it +appropriate permissions: + +#. Create `app:vpn:etc:vpn_ajohnson409_mgr`. +#. Add subject `ajohnson409` to this security group. +#. Grant *UPDATE* and *READ* access on the `...:ajohnson409` access control + list to this security group. +#. In a private browser window, log into the GTE was account `ajohnson409`, + password "password". You should be able to add and remove members from the + `vpn_ajohnson409` ACL. + +"""""""""""""""""""""" +Put Limits on Policies +"""""""""""""""""""""" + +It is the IAM team's responsibility to make sure that VPN access is granted to the +correct subjects. Putting some limits in place can help make sure improper +access is not granted. Attestation makes sure that access which was granted +in the past is still appropriate. + +#. Create `ref:iam:global_deny`. This reference group represents a broad cohort + of subjects that should not be granted access to most policies. Subjects + that fall into this category may be: + + * Termed "with cause" + * Deceased + * Other reasons + +#. Add `ref:iam:global_deny` to the `app:vpn:vpn_deny` policy. +#. Add attestation requirements to the `app:vpn:ref:vpn_ajohnson409` ACL. + + * Create attestation requirements (30 days). + * Review notification settings. + * View :guilabel:`home` -> :guilabel:`misc` -> :guilabel:`attestation settings`. + * Log in as `ajohnson409` and attest! + * View audit log to see who attested group. + +#. Add automatic age-off / lifecycle - exceptions only good for 180 days. + There are 2 techniques: + + * Add member, edit membership, add membership end date. + * Better approach, use grouper rule to automatically add end date to + members. See :ref:`the appendix <apdx-401.1.4-auto-end-date>` for + details. + +#. Use Grouper 2.4 affiliation-based deprovisioning. + +All access to VPN is now traceable to natural language policy and known +exceptions! Policy is enforced automatically and kept in sync with changing +subject attributes. Exceptions are known and managed with a defined +attestation lifecycle. VPN policy participates in the global deny policy. + +---------------- +Exercise 401.1.5 +---------------- + +*CISO is working on a investigation and wants to know if this particular NetID +"blee172" has access to the VPN now or in the past 90 days?* + +#. Navigate to `apps:vpn:vpn_authorized`. +#. Search for so-and-so. +#. Open up phpMyAdmin (https://localhost:8443/phpmyadmin/) +#. Open Views, Go to SQL tab, paste in + :ref:`PIT query <apdx-401.1.5-pit-query>`, Go! + +.. _apdx-401.1.5-pit-query: + +---------------- +Exercise 401.1.6 +---------------- + +*CISO wants to know if anyone on this list of NetIDs has access to the VPN? And +why?* + +#. Import list to a test group. +#. Intersect with `vpn_authorized`. +#. Trace membership to determine what level of access and why. + diff --git a/docs/401/401.2.rst b/docs/401/401.2.rst new file mode 100644 index 0000000..10db353 --- /dev/null +++ b/docs/401/401.2.rst @@ -0,0 +1,236 @@ +=========================== +401.2 MFA Policy Governance +=========================== + +------------------- +Learning Objectives +------------------- + +* Use Grouper policy to control Shibboleth MFA behavior +* Create `eduPersonEntitlement` value to represent desired MFA behavior +* Evolve digital policy to match changing natural language policy + +-------------- +Lab Components +-------------- + +* Shibboleth +* Grouper +* PSPNG +* OpenLDAP +* eduPerson schema - `eduPersonEntitlement` +* REFEDS MFA profile +* `Grouper Deployment Guide <https://spaces.at.internet2.edu/display/Grouper/Grouper+Deployment+Guide+Work+-TIER+Program>`_ + +-------- +Overview +-------- + +Your institution is deploying multi-factor authentication (MFA). The first +target application is Web SSO. Any account enabled for MFA will experience +common MFA behaviors sufficient to assert the REFEDS MFA profile during +WebSSO authentication. The project plan calls for an initial pilot phase, +followed by a number phases where different cohorts will be required or +may opt-in. During the initial pilot phase, select cohorts will be asked to +volunteer. Your mission, should you choose to accept, is to create and evolve +the digital policy necessary to achieve the project goals. + +---------------- +Exercise 401.2.1 +---------------- + +*Create initial MFA application folder set and policy in Grouper* + +#. Create `app:mfa:mfa_enabled|allow|deny`. +#. Create `app:mfa:ref:pilot`. This reference group is an access control + list (ACL) as opposed to ABAC policy. +#. Add `app:mfa:ref:pilot` to `app:mfa:mfa_enabled_allow`. + + +---------------- +Exercise 401.2.2 +---------------- + +*Establish an eduPersonEntitlement value to signal "MFA enabled"* + +We will assign a unique `eduPersonEntitilement` (ePE) value to LDAP accounts +that are MFA enabled. We choose the value +**http://tier.internet2.edu/mfa/enabled**. + +There are 2 steps to accomplish this: + +#. Assign PSPNG `provision_to` attribute (attribute def `provision_to_def`) + to `app:mfa:mfa_enabled` with a value of `pspng_entitlements`. +#. Configure PSPNG to provision this attribute. + + .. literalinclude:: examples/401.2.2-pspng-config.properties + :language: properties + :lines: 92-100 + :caption: grouper-loader.properties + :name: 401.2.2-pspng-groupofnames + :linenos: + +---------------- +Exercise 401.2.3 +---------------- + +*Configure Shibboleth IdP to honor MFA enabled ePE value and assert REFEDS +MFA profile* + +.. literalinclude:: examples/401.2.3-general-authn.xml + :language: xml + :emphasize-lines: 14, 16 + :lines: 112-130 + :caption: mfa-authn-config.xml + :linenos: + +.. literalinclude:: examples/401.2.3-mfa-authn-config.xml + :language: xml + :emphasize-lines: 25 + :lines: 53-86 + :caption: mfa-authn-config.xml + :linenos: + +Now have a working MFA policy. Adding new volunteers to the pilot is as easy as +adding members to the pilot group. The next rollout phase calls for onboarding +select departments, but allow for exceptions. + +---------------- +Exercise 401.2.4 +---------------- + +*Onboard select departments, but allow for exceptions* + +#. Add `ref:dept:its` to `app:mfa:mfa_enabled_allow`. +#. Add `app:mfa:ref:mfa_bypass` to `app:mfa:mfa_enabled_deny`. Add [NetID] to + `mfa_bypass` to exclude from `mfa_enabled`. +#. Athletics departement + + * You don't have a reference group, but you were provided a list of subject IDs: + + .. literalinclude:: examples/401.2.4-athletics-dept.txt + :language: text + :caption: Athletics Department + :linenos: + + * Import the list as a temporary app-specific reference group. + * Add this reference group to `mfa_enabled_allow`. + +The MFA pilot is going well when the institution is hit with some direct deposit +fraud. Mandate comes from leadership to add some required cohorts. The new +policy is "any non-faculty who has access to sensitive data (i.e. Banner +INB) must have mfa enabled". The new policy should be active within two days. + + +---------------- +Exercise 401.2.5 +---------------- + +*Update policy to include all non-faculty employees who have access to sensitive data in Banner* + +The Banner support team provides a list of NetIDs to satisfy the "non-faculty +who have access to sensitive data in Banner" part of the policy. + +#. Create `app:mfa:ref:NonFacultyBannerINB` and import list of NetIDs. + + .. literalinclude:: examples/401.2.5-banner-netids.txt + +#. Add `NonFacultyBannerINB` to `app:mfa:mfa_enabled_allow`. Edit the start + date for this group to be in the future. +#. Use :ref:`SQL <apdx-401.2.5-future-memberships-query>` to view memberships + enabled in the future. + +That’s was easy! Except-- the list is not quite right. Some faculty were +included for some reason. Help desk calling! Need to remove faculty members. + + +---------------- +Exercise 401.2.6 +---------------- + +*Update policy to include all Banner users except faculty* + +#. Create `app:mfa:ref:BannerUsersMinusFaculty`. +#. Edit this reference group to make it composite of `NonFacultyBannerINB` + minus `ref:faculty`. + +The new policy is in place and the pilot continues to expand. The next phase +calls for any faculty, staff, or student who are not already required to be +able to opt-in or out of MFA at their discretion. + + +---------------- +Exercise 401.2.7 +---------------- + +*Allow any faculty, staff, or student to opt-in/out if they are not already +required by other policy* + +#. Create `app:mfa:ref:mfa_opt_in`, an opt-in group for individuals who want to + join or leave the service. +#. Add `mfa_opt_in` to `mfa_enabled_allow`. +#. Create a new grouper security group, `app:mfa:etc:mfa_opt_in_access|allow|deny`. +#. Add faculty, staff, and student reference groups to + `app:mfa:etc:mfa_opt_in_access_allow`. +#. Create `app:mfa:ref:mfa_required` and copy your required members from the + `mfa_enabled_allow` policy to `mfa_required`. +#. Add `mfa_required` to `mfa_enabled_allow` and remove the redundant members. +#. Add `app:mfa:ref:mfa_required` to `mfa_opt_in_access_deny`. +#. Configure `mfa_opt_in` privileges to grant `mfa_opt_in_access` *OptIn* and + *OptOut* rights. + +Now, subject **awhite318** (Amber White) can log in and see the +`mfa_opt_in` group. This subject is able to join or leave at will. + +""""""""""""""""""""""""""""" +Improving the User Experience +""""""""""""""""""""""""""""" + +The Grouper UI is sufficient for simple user interaction, but not a great user +experience. Another approach is to build a small, web-based application to +manage membership directly or via database and grouper loader. + +* Web application maintains a database of NetIDs that have opted in. +* Grouper loader job imports opt-in members into a reerence group. +* The web app needs to know what NetIDs are required to use MFA and are + therefore ineligible to use the web app. Grouper can provision a 2nd + ePE, `http://tier.internet2.edu/mfa/required`. + +Working great! But, accounts that were put in early bypass for some reason +now can't opt-in. It looks like they enabled it, but they get filtered out of +`mfa_enabled` because of the bypass membership. Removing those accounts from +bypass puts them in `mfa_enabled`. + +---------------- +Exercise 401.2.8 +---------------- + +*Refactor `...:ref:bypass` to accommodate users who opt-in to MFA* + +#. Refactor `...:ref:bypass` to `...:basis:mfa_bypass`. +#. Create new `...:ref:mfa_bypass_not_opt_in` composite + (`...:basis:mfa_bypass` - `...:ref:mfa_opt_in`). +#. Add `...:ref:mfa_bypass_not_opt_in` to `app:mfa:mfa_enabled_deny`. + +Another way might be to use Grouper rules. + +Pilot has been a success. Leadership wants all remaining faculty, staff, +and students to be enabled by policy. + +---------------- +Exercise 401.2.9 +---------------- + +*Add all remaining faculty, staff, and students to policy* + +#. Add appropriate reference groups to allow policy. +#. Clean up intermediate policy and application reference groups. + + * Add `faculty`, `staff`, and `student` reference groups to policy. + * Remove app specific reference and basis groups. + +We should now have a fairly clean app policy folder. We were able to update +digital policy without affecting service. + +Kick back and have a margarita! + diff --git a/docs/401/401.3.rst b/docs/401/401.3.rst new file mode 100644 index 0000000..240a440 --- /dev/null +++ b/docs/401/401.3.rst @@ -0,0 +1,224 @@ +=============================== +401.3 Board Effect Provisioning +=============================== + +------------------- +Learning Objectives +------------------- + + +-------------- +Lab Components +-------------- + +* Shibboleth IdP +* InCommon Federation +* Grouper +* RabbitMQ +* Grouper ESBChangeLog Consumer +* `Grouper Deployment Guide`_ + +-------- +Overview +-------- + +We have been asked to deploy a SaaS application called Board Effect. The +service is already an InCommon member and honors an `eduPersonEntitlement` +for "front door" access. Permission management within the application is +centered around "work rooms". Each work room provide access to specific +documents, chat, mailing lists, etc. The system will be used by trustees, +executives, and various committee members. + +Thankfully the service is an InCommon member and using `eduPersonEntitlement` +values. However, it turns out users still need to have accounts provisioned +in order to get access. We will need two different kinds of policy groups. +The first, the account policy group, will be mapped to an `eduPersonEntitlement` +value and also be used for provisioning accounts. The second type, +authorization groups, will provide subject to role mapping, and are mapped +to work rooms created in Board Effect. This is an example of access control +model 3 described in the `Grouper Deployment Guide`_. + +---------------- +Exercise 401.3.1 +---------------- + +*Create a application policy folder and groups* + +Rather than create the basic structure manually, use a +:ref:`GSH script <apdx-401.3.1-app-skeleton>`. + + +---------------- +Exercise 401.3.2 +---------------- + +*Workrooms (i.e. authorization groups) can be updated via the Board Effect +REST API. Create Grouper authorization groups to manage those.* + +A new workroom call Committee on Finance has been created in Board Effect. +Need to create authorization group in grouper and configure provisioning. + +#. Create `app:boardeffect:wr_cmt_fin_authorized|allow|deny`. +#. Configure grouperESB to send membership changes to rabbitMQ exchange. + + .. literalinclude:: examples/401.3.2-grouper-loader.properties + :language: properties + :lines: 102-118 + :caption: grouper-loader.properties + :linenos: + + .. literalinclude:: examples/401.3.2-grouper.client.properties + :language: properties + :lines: 61-112 + :caption: grouper.client.properties + :linenos: + +#. Write provisioner component to read rabbitMQ and update BoardEffect via REST API. + + .. note:: + + This step is what logically should happen next to process the messages. + You aren't expected to actually accomplish this step during the lab. + +---------------- +Exercise 401.3.3 +---------------- + +*Board Effect account provisioning* + +#. Create `app:boardeffect:boardeffect_authorized`. +#. Add `...:wr_cmt_fin_authorized` to `boardeffect_authorized_allow`. +#. Configure PSPNG to write `eduPersonEntitlement` value + **https://college.boardeffect.com/** to LDAP and release via Shibboleth only + for Boardeffect. + + .. literalinclude:: examples/401.3.2-grouper-loader.properties + :language: properties + :lines: 92-100 + :emphasize-lines: 6 + :caption: grouper-loader.properties + :linenos: + +Subject to role mapping in place and provisioners working, but how do we get +reference groups for committees? Ann in President’s Office knows. + +---------------- +Exercise 401.3.4 +---------------- + +*Distributed Reference Group Management* + +Amy maintains list of committee members. Use these to build application specific +reference groups. + +#. Create `app:boardeffect:ref:cmt_fin`. +#. Add `...:ref:cmt_fin` to `...:wr_cmt_fin_allow`. +#. Add `ref:global_deny` to `...:wr_cmt_fin_deny`. +#. Give Ann admin access to `app:boardeffect:ref` by adding account + **amartinez410** to `app:boardeffect:etc:boardeffect_admins`. + +Log in as Ann Martinez (**amartinez410**). Under *My Groups* you should see +the reference groups and policies Ann can manage. + +---------------- +Exercise 401.3.5 +---------------- + +*Committee member helpers* + +Joe Trustee is on committee, but Joe’s assistant also needs access to +committee work group. + +#. Create app specific ref group `app:boardeffect:ref:cmt_fin_helpers`. +#. Add `...:cmt_fin_helpers. to `...:wr_cmt_fin_allow`. + +.. note:: + + By *not* adding the helper subject to `app:boardeffect:ref:cmt_fin`, + we preserve the truth of the subject attributes. Members of `cmt_fin` + *are* members of the Finance Committee. The helpers are *not* members + of the committee, but they *are* granted access to the workroom by + the policy. + +This works great for specific assistants, but there are also general helpers +who need access to all workrooms *temporarily* during board meetings. + +#. Create app specific ref group `app:boardeffect:ref:workroom_helpers`. +#. Run :ref:`GSH script <apdx-401.3.5-temp-access>` to add age off rule + to `workroom_helpers`. +#. Add `workroom_helpers` to all workroom allow groups. + +Workrooms created in Boardeffect. Grouper policy groups map to workroom, and +are kept up to date via Grouper provisioners. We could create workrooms +automatically based on policy group creation-- exercise left to student at home. + +---------------- +Exercise 401.3.6 +---------------- + +*Anna's Grouper Privileges* + +Anna was added as a direct member of `app:boardeffect:etc:boardeffect_admins`, +but we can do better! Responsibility for committee member management goes to +the president's executive assistant, whoever that might be. + +#. Create a new reference group (role), `ref:roles:president_assistant` + for president executive assistant. +#. Add Anna's account to `president_assistant`. + +This is better, but does Anna really need full admin privileges to +`app:boardeffect`? Probably only needs update / read. + +#. Add `ref:roles:president_assistant` to `app:boardeffect:etc:boardeffect_managers`. +#. Remove Anna from `app:boardeffect:etc:boardeffect_admins`. + + +---------------- +Exercise 401.3.7 +---------------- + +*Global Committee reference groups* + +All working great-- new system request comes in with policy based on board +committees. Need to elevate app-specific ref groups to global ref groups. + +#. Create `ref:board` folder for board committee ref groups. +#. Move `app:boardeffect:ref:cmt_fin` to `ref:board:cmt_fin`. + + .. note:: + + The Board Effect policies are not impacted by moving the location of + the reference groups! + +#. Create `ref:board:etc` security folder. +#. Create `ref:board:etc:board_managers` security group. +#. Assign *UPDATE* and *READ* rights on reference groups to `board_managers`. +#. Revoke *UPDATE* and *READ* rights of reference groups from `app:board_effect:etc:boardeffect_managers`. + + .. warning:: + + Moving our reference groups did *not* remove the access we had granted + on them from application-specific security groups. After moving a + reference group, it is good practive to review its permissions. + +#. Add `president_assistant` to `ref:board:etc:board_managers`. + + +-------- +Epilogue +-------- + +New request comes in for four advisory councils. Each will have their own +workroom in Board Effect. Initially you are handed a spreadsheet with the +council members and you import them into app-specific reference groups +(e.g. `app:boardeffect:ref:advisory_council_northeast`). Later you find +out that council membership is available in Banner, so you create loader +jobs for those. As it turns out, the spreadsheets were old and had the wrong +members. Thank goodness for loader jobs! Alas, not all advisory council +members have NetIDs. To get them access we add them as sponsored accounts +in COmanage. + +The End + + +.. _Grouper Deployment Guide: https://spaces.at.internet2.edu/display/Grouper/Grouper+Deployment+Guide+Work+-TIER+Program diff --git a/docs/401/401.4-example-solution.rst b/docs/401/401.4-example-solution.rst new file mode 100644 index 0000000..4aba227 --- /dev/null +++ b/docs/401/401.4-example-solution.rst @@ -0,0 +1,26 @@ + +========================================================== +401.4 Untangling Legacy Access Policies - Example Solution +========================================================== + +The follwing solution uses techniques demonstrated in the other 401 series +labs in order to create an independent policy for the LMS service. + +#. Use Grouper Loader to import existing LDAP cohort group into a "community + members" reference group-- `ref:legacy:community_members` +#. Add loader job to populate `communtiy_members` from + `cn=community_members,ou=groups,dc=example,dc=edu`. +#. Run loader job to import members into reference group. +#. Create a Grouper service folder for the LMS with a policy for LMS + authorization: `app:lms:lms_authorize|allow|deny` +#. Add the "institutional people" reference group, `ref:community_members`, + to the allow policy for the LMS, `app:lms:lms_allow`. +#. Create `app:lms:ref:visiting_scholars`. Import the NetIDs for the visiting + scholors into this reference group. +#. Add `visiting_scholars` to `lms_allow`. +#. Provision this policy to a new group in the LDAP DIT that the LMS group can + use to allow access to the service. + +Congrats! You are now a certified Grouper Guru associate level 1! +And remember nothing gets'em going like chum! + diff --git a/docs/401/401.4.rst b/docs/401/401.4.rst new file mode 100644 index 0000000..712f57d --- /dev/null +++ b/docs/401/401.4.rst @@ -0,0 +1,67 @@ +====================================== +401.4 Untangling Legacy Access Polcies +====================================== + +------------------- +Learning Objectives +------------------- + +* Learn to recognize tangled access control policies. +* Use techniques to untangle co-mingled policies and cohorts. + +-------------- +Lab Components +-------------- + +* Grouper + +-------- +Overview +-------- + +A baseline of core services services are enabled by default for a broad range of +community cohorts. The current approach uses a hodge-podge of scripts and +manual intervention to establish a group of "institutional people" that are +granted access to a wide range of services. The system can best be described as +fragile, brittle, and difficult, if not impossible, to evolve and maintain. In +other words-- state of the industry. + +Last year your CIO came back from Internet2 Summit and declared that your +institution is going to deploy TIER. You've just managed to get the Grouper +software up and running, when the head of your LMS group, Vicky, bursts into your +office space and tells you that there are 50 visiting scholars showing up on +campus tomorrow, and they all need access to the LMS for a campus-wide lecture +series. + +Your co-worker had mentioned this to you before she left for her month long +vacation. She had told you she had taken care of creating the guest accounts, +and not to worry. You just need to grant access to the LMS when the time comes. +No problem. + +But suddenly, you realize that access is controlled via the "institutional +people" group in your Enterprise Directory Information Tree! If you add the +scholars to that group, they'll have access to everything on campus! + +Before panic sets in, you remember your Grouper training. You'll need a little +help from Vicky, but with Grouper, you've got this covered. "OK, Vicky," you say +in a calm, steady voice. "Here's what I'm going to need your team to do ..." + +---------------- +Exercise 401.4.1 +---------------- + +*Untangling Policies from Cohorts* + +The goal of this exercise is to grant access to the LMS for the 50 visiting +scholar guest accounts *without* granting additional access to those accounts. +Since access control does not happen in a vacuum, you'll need some minimal +assistance from the LMS team. Vicky's team can configure the LMS to point to a +new group in the LDAP DIT, but that's all the help you'll get. + +The basic issue is that the legacy access control mechanisms are based on a +cohort of loosely defined "institutional people". All your institution's services +are using this cohort directly to determine who is supposed to have access. + +You'll need to use your new Grouper skills to resolve this issue. + + diff --git a/docs/401/appendix.rst b/docs/401/appendix.rst new file mode 100644 index 0000000..81a25d4 --- /dev/null +++ b/docs/401/appendix.rst @@ -0,0 +1,217 @@ +======== +Appendix +======== + +.. _apdx-401.1.4-auto-end-date: + +------------------------------- +401.1.4 Automatic End Date Rule +------------------------------- + +To configure the automatic rule end date on the access control list, +`app:vpn:ref:vpn_adhoc` you must use the Grouper Shell (GSH) to run +a short script. To run GSH, you must connect to the GTE container +that has the Grouper API installed: + +.. code-block:: bash + + root# docker exec -it CONTAINER_NAME /bin/bash + bash# cd bin + bash# gsh + +At this point you can paste in the following script: + +.. code-block:: groovy + :emphasize-lines: 1,3 + :linenos: + + numDays = 180; + actAs = SubjectFinder.findRootSubject(); + vpn_adhoc = getGroups("app:vpn:ref:vpn_adhoc")[0]; + attribAssign = vpn_adhoc.getAttributeDelegate().addAttribute(RuleUtils.ruleAttributeDefName()).getAttributeAssign(); + attribValueDelegate = attribAssign.getAttributeValueDelegate(); + attribValueDelegate.assignValue(RuleUtils.ruleActAsSubjectSourceIdName(), actAs.getSourceId()); + attribValueDelegate.assignValue(RuleUtils.ruleRunDaemonName(), "F"); + attribValueDelegate.assignValue(RuleUtils.ruleActAsSubjectIdName(), actAs.getId()); + attribValueDelegate.assignValue(RuleUtils.ruleCheckTypeName(), RuleCheckType.membershipAdd.name()); + attribValueDelegate.assignValue(RuleUtils.ruleIfConditionEnumName(), RuleIfConditionEnum.thisGroupHasImmediateEnabledNoEndDateMembership.name()); + attribValueDelegate.assignValue(RuleUtils.ruleThenEnumName(), RuleThenEnum.assignMembershipDisabledDaysForOwnerGroupId.name()); + attribValueDelegate.assignValue(RuleUtils.ruleThenEnumArg0Name(), numDays.toString()); + attribValueDelegate.assignValue(RuleUtils.ruleThenEnumArg1Name(), "T"); + +.. _apdx-401.1.5-pit-query: + +-------------------------------------- +401.1.5 Point-in-Time Membership Query +-------------------------------------- + +.. code-block:: sql + :linenos: + + SELECT + gpm.SUBJECT_ID, + gpg.NAME, + FROM_UNIXTIME(gpmav.MEMBERSHIP_START_TIME / 1000000) start_time, + FROM_UNIXTIME(gpmav.MEMBERSHIP_END_TIME / 1000000) end_time + FROM grouper_pit_memberships_all_v gpmav + INNER JOIN grouper_pit_groups gpg + ON gpmav.owner_group_id = gpg.id + INNER JOIN grouper_pit_members gpm + ON gpmav.MEMBER_ID = gpm.id + INNER JOIN grouper_pit_fields gpf + ON gpmav.field_id = gpf.id + WHERE gpg.name = 'app:vpn:vpn_authorized' + AND gpm.subject_type = 'person' + AND gpf.name = 'members' + ORDER BY gpmav.MEMBERSHIP_START_TIME DESC + ; + + +.. _apdx-401.2.5-future-memberships-query: + +-------------------------------- +401.2.5 Future Memberships Query +-------------------------------- + +.. code-block:: sql + :linenos: + + SELECT + ggv.name, + FROM_UNIXTIME(gmav.IMMEDIATE_MSHIP_ENABLED_TIME / 1000) enabled_time, + CASE + WHEN gm.subject_type = 'group' THEN gm.subject_identifier0 + ELSE gm.subject_id + END member + FROM `grouper_memberships_all_v` gmav + INNER JOIN grouper_groups_v ggv + ON gmav.OWNER_GROUP_ID = ggv.GROUP_ID + INNER JOIN grouper_members gm + ON gmav.member_id = gm.id + WHERE gmav.IMMEDIATE_MSHIP_ENABLED_TIME IS NOT NULL + ; + +.. _apdx-401.3.1-app-skeleton: + +----------------------------------- +401.3.1 Application Skeleton Script +----------------------------------- + +This script automatically creates an application folder along with +security groups and permission rules. +You must use the Grouper Shell (GSH) to run +a short script. To run GSH, you must connect to the GTE container +that has the Grouper API installed: + +.. code-block:: bash + + root# docker exec -it CONTAINER_NAME /bin/bash + bash# cd bin + bash# gsh + +At this point you can paste in the following script: + +.. code-block:: groovy + :emphasize-lines: 3,4 + :linenos: + + // SET THESE + parent_stem_path = "app"; + app_extension = "boardeffect"; + app_name = "Board Effect"; + + + if (!app_name?.trim()) + { + app_name = app_extension; + } + + def makeStemInheritable(obj, stemName, groupName, priv="admin") { + baseStem = obj.getStems(stemName)[0]; + aGroup = obj.getGroups(groupName)[0]; + RuleApi.inheritGroupPrivileges( + SubjectFinder.findRootSubject(), + baseStem, + Stem.Scope.SUB, + aGroup.toSubject(), + Privilege.getInstances(priv) + ); + RuleApi.runRulesForOwner(baseStem); + if(priv == 'admin') + { + RuleApi.inheritFolderPrivileges( + SubjectFinder.findRootSubject(), + baseStem, + Stem.Scope.SUB, + aGroup.toSubject(), + Privilege.getInstances("stem, create")); + } + RuleApi.runRulesForOwner(baseStem); + } + + stem = addStem(parent_stem_path, app_extension, app_name); + etc_stem = addStem(stem.name, "etc", "etc"); + admin_group_name = "${app_extension}_admins"; + admin_group = addGroup(etc_stem.name, admin_group_name, admin_group_name); + admin_group.grantPriv(admin_group.toMember().getSubject(), AccessPrivilege.ADMIN); + mgr_group_name = "${app_extension}_mgr"; + mgr_group = addGroup(etc_stem.name, mgr_group_name, mgr_group_name); + mgr_group.grantPriv(admin_group.toMember().getSubject(), AccessPrivilege.ADMIN); + mgr_group.grantPriv(mgr_group.toMember().getSubject(), AccessPrivilege.UPDATE); + mgr_group.grantPriv(mgr_group.toMember().getSubject(), AccessPrivilege.READ); + view_group_name = "${app_extension}_viewers"; + view_group = addGroup(etc_stem.name, view_group_name, view_group_name); + view_group.grantPriv(view_group.toMember().getSubject(), AccessPrivilege.READ); + view_group.grantPriv(admin_group.toMember().getSubject(), AccessPrivilege.ADMIN); + view_group.grantPriv(mgr_group.toMember().getSubject(), AccessPrivilege.UPDATE); + view_group.grantPriv(mgr_group.toMember().getSubject(), AccessPrivilege.READ); + admin_group.grantPriv(view_group.toMember().getSubject(), AccessPrivilege.READ); + mgr_group.grantPriv(view_group.toMember().getSubject(), AccessPrivilege.READ); + // Child objects should also grant perms to these groups. + makeStemInheritable(this, stem.name, admin_group.name, 'admin'); + makeStemInheritable(this, stem.name, mgr_group.name, 'update'); + makeStemInheritable(this, stem.name, mgr_group.name, 'read'); + makeStemInheritable(this, stem.name, view_group.name, 'read'); + admin_group.revokePriv(mgr_group.toMember().getSubject(), AccessPrivilege.UPDATE); + +.. _apdx-401.3.5-temp-access: + +------------------------------- +401.3.1 Temporary Access Script +------------------------------- + +This script automatically creates an application folder along with +security groups and permission rules. +You must use the Grouper Shell (GSH) to run +a short script. To run GSH, you must connect to the GTE container +that has the Grouper API installed: + +.. code-block:: bash + + root# docker exec -it CONTAINER_NAME /bin/bash + bash# cd bin + bash# gsh + +At this point you can paste in the following script: + +.. code-block:: groovy + :emphasize-lines: 2,3 + :linenos: + + // Script parameters + group_name = "app:boardeffect:ref:workroom_helpers"; + numDays = 3; + + actAs = SubjectFinder.findRootSubject(); + vpn_adhoc = getGroups(group_name)[0]; + attribAssign = vpn_adhoc.getAttributeDelegate().addAttribute(RuleUtils.ruleAttributeDefName()).getAttributeAssign(); + attribValueDelegate = attribAssign.getAttributeValueDelegate(); + attribValueDelegate.assignValue(RuleUtils.ruleActAsSubjectSourceIdName(), actAs.getSourceId()); + attribValueDelegate.assignValue(RuleUtils.ruleRunDaemonName(), "F"); + attribValueDelegate.assignValue(RuleUtils.ruleActAsSubjectIdName(), actAs.getId()); + attribValueDelegate.assignValue(RuleUtils.ruleCheckTypeName(), RuleCheckType.membershipAdd.name()); + attribValueDelegate.assignValue(RuleUtils.ruleIfConditionEnumName(), RuleIfConditionEnum.thisGroupHasImmediateEnabledNoEndDateMembership.name()); + attribValueDelegate.assignValue(RuleUtils.ruleThenEnumName(), RuleThenEnum.assignMembershipDisabledDaysForOwnerGroupId.name()); + attribValueDelegate.assignValue(RuleUtils.ruleThenEnumArg0Name(), numDays.toString()); + attribValueDelegate.assignValue(RuleUtils.ruleThenEnumArg1Name(), "T"); + diff --git a/docs/401/examples/401.1.3-pspng-config.properties b/docs/401/examples/401.1.3-pspng-config.properties new file mode 100644 index 0000000..9f356a1 --- /dev/null +++ b/docs/401/examples/401.1.3-pspng-config.properties @@ -0,0 +1,90 @@ +#specify the consumers here. specify the consumer name after the changeLog.consumer. part. This example is "psp" +#but it could be changeLog.consumer.myConsumerName.class +#the class must extend edu.internet2.middleware.grouper.changeLog.ChangeLogConsumerBase +#changeLog.consumer.psp.class = edu.internet2.middleware.psp.grouper.PspChangeLogConsumer + +#the quartz cron is a cron-like string. it defaults to every minute on the minute (since the temp to change log job runs +#at 10 seconds to each minute). it defaults to this: 0 * * * * ? +#though it will stagger each one by 2 seconds +# http://www.quartz-scheduler.org/documentation/quartz-1.x/tutorials/crontrigger +#changeLog.consumer.psp.quartzCron = 0 * * * * ? + +# To retry processing a change log entry if an error occurs, set retryOnError to true. Defaults to false. +#changeLog.consumer.psp.retryOnError = false + +# To run full provisioning synchronizations periodically, provide the class name which provides a 'public void fullSync()' method. +#changeLog.psp.fullSync.class = edu.internet2.middleware.psp.grouper.PspChangeLogConsumer + +# Schedule full synchronizations. Defaults to 5 am : 0 0 5 * * ?. +#changeLog.psp.fullSync.quartzCron = 0 0 5 * * ? + +# Run a full synchronization job at startup. Defaults to false. +#changeLog.psp.fullSync.runAtStartup = false + +# Omit diff responses from bulk response to conserve memory. +#changeLog.psp.fullSync.omitDiffResponses = true + +# Omit sync responses from bulk response to conserve memory. +#changeLog.psp.fullSync.omitSyncResponses = true + +################################# +## LDAP connections +################################# +# specify the ldap connection with user, pass, url +# the string after "ldap." is the ID of the connection, and it should not have +# spaces or other special chars in it. In this case is it "personLdap" + +#note the URL should start with ldap: or ldaps: if it is SSL. +#It should contain the server and port (optional if not default), and baseDn, +#e.g. ldaps://ldapserver.school.edu:636/dc=school,dc=edu +ldap.demo.url = ldap://localhost:389/ + +#optional, if authenticated +ldap.demo.user = cn=root,dc=internet2,dc=edu + +#optional, if authenticated note the password can be stored encrypted in an external file +ldap.demo.pass = password + +#optional, if you are using tls, set this to true. Generally you will not be using an SSL URL to use TLS... +ldap.demo.tls = false + +#optional, if using sasl +#ldap.personLdap.saslAuthorizationId = +#ldap.personLdap.saslRealm = + +#optional (note, time limit is for search operations, timeout is for connection timeouts), +#most of these default to vt-ldap defaults. times are in millis +#validateOnCheckout defaults to true if all other validate methods are false +#ldap.personLdap.batchSize = +#ldap.personLdap.countLimit = +#ldap.personLdap.timeLimit = +#ldap.personLdap.timeout = +#ldap.personLdap.minPoolSize = +#ldap.personLdap.maxPoolSize = +#ldap.personLdap.validateOnCheckIn = +#ldap.personLdap.validateOnCheckOut = +#ldap.personLdap.validatePeriodically = +#ldap.personLdap.validateTimerPeriod = +#ldap.personLdap.pruneTimerPeriod = +#if connections expire after a certain amount of time, this is it, in millis, defaults to 300000 (5 minutes) +#ldap.personLdap.expirationTime = + +#make the paths fully qualified and not relative to the loader group. +loader.ldap.requireTopStemAsStemFromConfigGroup=false + +changeLog.consumer.pspng_groupOfNames.class = edu.internet2.middleware.grouper.pspng.PspChangelogConsumerShim +changeLog.consumer.pspng_groupOfNames.type = edu.internet2.middleware.grouper.pspng.LdapGroupProvisioner +changeLog.consumer.pspng_groupOfNames.quartzCron = 0 * * * * ? +changeLog.consumer.pspng_groupOfNames.ldapPoolName = demo +changeLog.consumer.pspng_groupOfNames.supportsEmptyGroups = false +changeLog.consumer.pspng_groupOfNames.memberAttributeName = member +changeLog.consumer.pspng_groupOfNames.memberAttributeValueFormat = ${ldapUser.getDn()} +changeLog.consumer.pspng_groupOfNames.groupSearchBaseDn = ou=groups,dc=internet2,dc=edu +changeLog.consumer.pspng_groupOfNames.allGroupsSearchFilter = objectclass=groupOfNames +changeLog.consumer.pspng_groupOfNames.singleGroupSearchFilter = (&(objectclass=groupOfNames)(cn=${group.name})) +changeLog.consumer.pspng_groupOfNames.groupSearchAttributes = cn,objectclass +changeLog.consumer.pspng_groupOfNames.groupCreationLdifTemplate = dn: cn=${group.name}||cn: ${group.name}||objectclass: groupOfNames +changeLog.consumer.pspng_groupOfNames.userSearchBaseDn = ou=people,dc=internet2,dc=edu +changeLog.consumer.pspng_groupOfNames.userSearchFilter = uid=${subject.id} +changeLog.consumer.pspng_groupOfNames.grouperIsAuthoritative = false + diff --git a/docs/401/examples/401.2.2-pspng-config.properties b/docs/401/examples/401.2.2-pspng-config.properties new file mode 100644 index 0000000..1050e7f --- /dev/null +++ b/docs/401/examples/401.2.2-pspng-config.properties @@ -0,0 +1,100 @@ +#specify the consumers here. specify the consumer name after the changeLog.consumer. part. This example is "psp" +#but it could be changeLog.consumer.myConsumerName.class +#the class must extend edu.internet2.middleware.grouper.changeLog.ChangeLogConsumerBase +#changeLog.consumer.psp.class = edu.internet2.middleware.psp.grouper.PspChangeLogConsumer + +#the quartz cron is a cron-like string. it defaults to every minute on the minute (since the temp to change log job runs +#at 10 seconds to each minute). it defaults to this: 0 * * * * ? +#though it will stagger each one by 2 seconds +# http://www.quartz-scheduler.org/documentation/quartz-1.x/tutorials/crontrigger +#changeLog.consumer.psp.quartzCron = 0 * * * * ? + +# To retry processing a change log entry if an error occurs, set retryOnError to true. Defaults to false. +#changeLog.consumer.psp.retryOnError = false + +# To run full provisioning synchronizations periodically, provide the class name which provides a 'public void fullSync()' method. +#changeLog.psp.fullSync.class = edu.internet2.middleware.psp.grouper.PspChangeLogConsumer + +# Schedule full synchronizations. Defaults to 5 am : 0 0 5 * * ?. +#changeLog.psp.fullSync.quartzCron = 0 0 5 * * ? + +# Run a full synchronization job at startup. Defaults to false. +#changeLog.psp.fullSync.runAtStartup = false + +# Omit diff responses from bulk response to conserve memory. +#changeLog.psp.fullSync.omitDiffResponses = true + +# Omit sync responses from bulk response to conserve memory. +#changeLog.psp.fullSync.omitSyncResponses = true + +################################# +## LDAP connections +################################# +# specify the ldap connection with user, pass, url +# the string after "ldap." is the ID of the connection, and it should not have +# spaces or other special chars in it. In this case is it "personLdap" + +#note the URL should start with ldap: or ldaps: if it is SSL. +#It should contain the server and port (optional if not default), and baseDn, +#e.g. ldaps://ldapserver.school.edu:636/dc=school,dc=edu +ldap.demo.url = ldap://localhost:389/ + +#optional, if authenticated +ldap.demo.user = cn=root,dc=internet2,dc=edu + +#optional, if authenticated note the password can be stored encrypted in an external file +ldap.demo.pass = password + +#optional, if you are using tls, set this to true. Generally you will not be using an SSL URL to use TLS... +ldap.demo.tls = false + +#optional, if using sasl +#ldap.personLdap.saslAuthorizationId = +#ldap.personLdap.saslRealm = + +#optional (note, time limit is for search operations, timeout is for connection timeouts), +#most of these default to vt-ldap defaults. times are in millis +#validateOnCheckout defaults to true if all other validate methods are false +#ldap.personLdap.batchSize = +#ldap.personLdap.countLimit = +#ldap.personLdap.timeLimit = +#ldap.personLdap.timeout = +#ldap.personLdap.minPoolSize = +#ldap.personLdap.maxPoolSize = +#ldap.personLdap.validateOnCheckIn = +#ldap.personLdap.validateOnCheckOut = +#ldap.personLdap.validatePeriodically = +#ldap.personLdap.validateTimerPeriod = +#ldap.personLdap.pruneTimerPeriod = +#if connections expire after a certain amount of time, this is it, in millis, defaults to 300000 (5 minutes) +#ldap.personLdap.expirationTime = + +#make the paths fully qualified and not relative to the loader group. +loader.ldap.requireTopStemAsStemFromConfigGroup=false + +changeLog.consumer.pspng_groupOfNames.class = edu.internet2.middleware.grouper.pspng.PspChangelogConsumerShim +changeLog.consumer.pspng_groupOfNames.type = edu.internet2.middleware.grouper.pspng.LdapGroupProvisioner +changeLog.consumer.pspng_groupOfNames.quartzCron = 0 * * * * ? +changeLog.consumer.pspng_groupOfNames.ldapPoolName = demo +changeLog.consumer.pspng_groupOfNames.supportsEmptyGroups = false +changeLog.consumer.pspng_groupOfNames.memberAttributeName = member +changeLog.consumer.pspng_groupOfNames.memberAttributeValueFormat = ${ldapUser.getDn()} +changeLog.consumer.pspng_groupOfNames.groupSearchBaseDn = ou=groups,dc=internet2,dc=edu +changeLog.consumer.pspng_groupOfNames.allGroupsSearchFilter = objectclass=groupOfNames +changeLog.consumer.pspng_groupOfNames.singleGroupSearchFilter = (&(objectclass=groupOfNames)(cn=${group.name})) +changeLog.consumer.pspng_groupOfNames.groupSearchAttributes = cn,objectclass +changeLog.consumer.pspng_groupOfNames.groupCreationLdifTemplate = dn: cn=${group.name}||cn: ${group.name}||objectclass: groupOfNames +changeLog.consumer.pspng_groupOfNames.userSearchBaseDn = ou=people,dc=internet2,dc=edu +changeLog.consumer.pspng_groupOfNames.userSearchFilter = uid=${subject.id} +changeLog.consumer.pspng_groupOfNames.grouperIsAuthoritative = false + + +changeLog.consumer.pspng_entitlements.class = edu.internet2.middleware.grouper.pspng.PspChangelogConsumerShim +changeLog.consumer.pspng_entitlements.type = edu.internet2.middleware.grouper.pspng.LdapAttributeProvisioner +changeLog.consumer.pspng_entitlements.quartzCron = 0 * * * * ? +changeLog.consumer.pspng_entitlements.ldapPoolName = demo +changeLog.consumer.pspng_entitlements.provisionedAttributeName = eduPersonEntitlement +changeLog.consumer.pspng_entitlements.provisionedAttributeValueFormat = ${group.name.equalsIgnoreCase('app:mfa:mfa_enabled') ? 'http://tier.internet2.edu/mfa/enabled' : 'urn:mace:example.edu:' + group.extension} +changeLog.consumer.pspng_entitlements.userSearchBaseDn = ou=people,dc=internet2,dc=edu +changeLog.consumer.pspng_entitlements.userSearchFilter = uid=${subject.id} +changeLog.consumer.pspng_entitlements.allProvisionedValuesPrefix=* diff --git a/docs/401/examples/401.2.3-general-authn.xml b/docs/401/examples/401.2.3-general-authn.xml new file mode 100644 index 0000000..152d8e2 --- /dev/null +++ b/docs/401/examples/401.2.3-general-authn.xml @@ -0,0 +1,181 @@ +<?xml version="1.0" encoding="UTF-8"?> +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:context="http://www.springframework.org/schema/context" + xmlns:util="http://www.springframework.org/schema/util" + xmlns:p="http://www.springframework.org/schema/p" + xmlns:c="http://www.springframework.org/schema/c" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd + http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd" + + default-init-method="initialize" + default-destroy-method="destroy"> + + <!-- + This file provisions the IdP with information about the configured login mechanisms available for use. + The actual beans and subflows that make up those mechanisms are in their own files, but this pulls them + together with deployer-supplied metadata to describe them to the system. + + You can turn on and off individual mechanisms by adding and remove them here. Nothing left out will + be used, regardless any other files loaded by the Spring container. + + Flow defaults include: no support for IsPassive/ForceAuthn, support for non-browser clients enabled, + and default timeout and lifetime values set via properties. We also default to supporting the SAML 1/2 + expressions for password-based authentication over a secure channel, so anything more exotic requires + customization, as the examples below for IP address and SPNEGO authentication illustrate. + --> + + <util:list id="shibboleth.AvailableAuthenticationFlows"> + + <bean id="authn/IPAddress" parent="shibboleth.AuthenticationFlow" + p:passiveAuthenticationSupported="true" + p:lifetime="PT60S" p:inactivityTimeout="PT60S"> + <property name="supportedPrincipals"> + <list> + <bean parent="shibboleth.SAML2AuthnContextClassRef" + c:classRef="urn:oasis:names:tc:SAML:2.0:ac:classes:InternetProtocol" /> + </list> + </property> + </bean> + + <bean id="authn/SPNEGO" parent="shibboleth.AuthenticationFlow" + p:nonBrowserSupported="false"> + <property name="supportedPrincipals"> + <list> + <bean parent="shibboleth.SAML2AuthnContextClassRef" + c:classRef="urn:oasis:names:tc:SAML:2.0:ac:classes:Kerberos" /> + <bean parent="shibboleth.SAML1AuthenticationMethod" + c:method="urn:ietf:rfc:1510" /> + </list> + </property> + </bean> + + <bean id="authn/External" parent="shibboleth.AuthenticationFlow" + p:nonBrowserSupported="false" /> + + <bean id="authn/RemoteUser" parent="shibboleth.AuthenticationFlow" + p:nonBrowserSupported="false" /> + + <bean id="authn/RemoteUserInternal" parent="shibboleth.AuthenticationFlow" /> + + <bean id="authn/X509" parent="shibboleth.AuthenticationFlow" + p:nonBrowserSupported="false"> + <property name="supportedPrincipals"> + <list> + <bean parent="shibboleth.SAML2AuthnContextClassRef" + c:classRef="urn:oasis:names:tc:SAML:2.0:ac:classes:X509" /> + <bean parent="shibboleth.SAML2AuthnContextClassRef" + c:classRef="urn:oasis:names:tc:SAML:2.0:ac:classes:TLSClient" /> + <bean parent="shibboleth.SAML1AuthenticationMethod" + c:method="urn:ietf:rfc:2246" /> + </list> + </property> + </bean> + + <bean id="authn/X509Internal" parent="shibboleth.AuthenticationFlow"> + <property name="supportedPrincipals"> + <list> + <bean parent="shibboleth.SAML2AuthnContextClassRef" + c:classRef="urn:oasis:names:tc:SAML:2.0:ac:classes:X509" /> + <bean parent="shibboleth.SAML2AuthnContextClassRef" + c:classRef="urn:oasis:names:tc:SAML:2.0:ac:classes:TLSClient" /> + <bean parent="shibboleth.SAML1AuthenticationMethod" + c:method="urn:ietf:rfc:2246" /> + </list> + </property> + </bean> + + <bean id="authn/Password" parent="shibboleth.AuthenticationFlow" + p:passiveAuthenticationSupported="true" + p:forcedAuthenticationSupported="true" /> + + <bean id="authn/Duo" parent="shibboleth.AuthenticationFlow" + p:forcedAuthenticationSupported="true" + p:nonBrowserSupported="false"> + <!-- + The list below should be changed to reflect whatever locally- or + community-defined values are appropriate to represent MFA. It is + strongly advised that the value not be specific to Duo or any + particular technology. + --> + <property name="supportedPrincipals"> + <list> + <bean parent="shibboleth.SAML2AuthnContextClassRef" + c:classRef="http://example.org/ac/classes/mfa" /> + <bean parent="shibboleth.SAML1AuthenticationMethod" + c:method="http://example.org/ac/classes/mfa" /> + </list> + </property> + </bean> + + <!-- A Mock MFA provider for this tutorial --> + <bean id="authn/Gaspo" parent="shibboleth.AuthenticationFlow" + p:forcedAuthenticationSupported="true" + p:nonBrowserSupported="false"> + <!-- + The list below should be changed to reflect whatever locally- or + community-defined values are appropriate to represent MFA. It is + strongly advised that the value not be specific to Duo or any + particular technology. + --> + <property name="supportedPrincipals"> + <list> + <bean parent="shibboleth.SAML2AuthnContextClassRef" + c:classRef="https://refeds.org/profile/mfa" /> + <bean parent="shibboleth.SAML1AuthenticationMethod" + c:method="https://refeds.org/profile/mfa" /> + </list> + </property> + </bean> + + <bean id="authn/MFA" parent="shibboleth.AuthenticationFlow" + p:passiveAuthenticationSupported="true" + p:forcedAuthenticationSupported="true"> + <!-- + The list below almost certainly requires changes, and should generally be the + union of any of the separate factors you combine in your particular MFA flow + rules. The example corresponds to the example in mfa-authn-config.xml that + combines GaspoMFA with Password. + --> + <property name="supportedPrincipals"> + <list> + <bean parent="shibboleth.SAML2AuthnContextClassRef" + c:classRef="urn:oasis:names:tc:SAML:2.0:ac:classes:InternetProtocol" /> + <bean parent="shibboleth.SAML2AuthnContextClassRef" + c:classRef="urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport" /> + <bean parent="shibboleth.SAML2AuthnContextClassRef" + c:classRef="urn:oasis:names:tc:SAML:2.0:ac:classes:Password" /> + <bean parent="shibboleth.SAML1AuthenticationMethod" + c:method="urn:oasis:names:tc:SAML:1.0:am:password" /> + <bean parent="shibboleth.SAML2AuthnContextClassRef" + c:classRef="https://refeds.org/profile/mfa" /> + <bean parent="shibboleth.SAML1AuthenticationMethod" + c:method="https://refeds.org/profile/mfa" /> + + </list> + </property> + </bean> + + </util:list> + + <!-- + This is a map used to "weight" particular methods above others if the IdP has to randomly select one + to insert into a SAML authentication statement. The typical use shown below is to bias the IdP in favor + of expressing the SAML 2 PasswordProtectedTransport class over the more vanilla Password class on the + assumption that the IdP doesn't accept passwords via an insecure channel. This map never causes the IdP + to violate its matching rules if an RP requests a particular value; it only matters when nothing specific + is chosen. Anything not in the map has a weight of zero. + --> + + <util:map id="shibboleth.AuthenticationPrincipalWeightMap"> + <entry> + <key> + <bean parent="shibboleth.SAML2AuthnContextClassRef" + c:classRef="urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport" /> + </key> + <value>1</value> + </entry> + </util:map> + +</beans> diff --git a/docs/401/examples/401.2.3-mfa-authn-config.xml b/docs/401/examples/401.2.3-mfa-authn-config.xml new file mode 100644 index 0000000..f40a3de --- /dev/null +++ b/docs/401/examples/401.2.3-mfa-authn-config.xml @@ -0,0 +1,88 @@ +<?xml version="1.0" encoding="UTF-8"?> +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:context="http://www.springframework.org/schema/context" + xmlns:util="http://www.springframework.org/schema/util" + xmlns:p="http://www.springframework.org/schema/p" + xmlns:c="http://www.springframework.org/schema/c" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd + http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd" + + default-init-method="initialize" + default-destroy-method="destroy"> + + <!-- + This is a map of transition rules that guide the behavior of the MFA flow + and controls how factors are sequenced, skipped, etc. The key of each entry + is the name of the step/flow out of which control is passing. The starting + rule has an empty key. + Each entry is a bean inherited from "shibboleth.authn.MFA.Transition". Per + the Javadoc for net.shibboleth.idp.authn.MultiFactorAuthenticationTransition: + p:nextFlow (String) + - A flow to run if the previous step signaled a "proceed" event, for simple + transitions. + p:nextFlowStrategy (Function<ProfileRequestContext,String>) + - A function to run if the previous step signaled a "proceed" event, for dynamic + transitions. Returning null ends the MFA process. + p:nextFlowStrategyMap (Map<String,Object> where Object is String or Function<ProfileRequestContext,String>) + - Fully dynamic way of expressing control paths. Map is keyed by a previously + signaled event and the value is a flow to run or a function to + return the flow to run. Returning null ends the MFA process. + When no rule is provided, there's an implicit "null" that ends the MFA flow + with whatever event was last signaled. If the "proceed" event from a step is + the final event, then the MFA process attempts to complete itself successfully. + --> + <util:map id="shibboleth.authn.MFA.TransitionMap"> + <!-- First rule runs the IPAddress login flow. --> + <entry key=""> + <bean parent="shibboleth.authn.MFA.Transition" p:nextFlow="authn/Password" /> + </entry> + + <!-- + Second rule runs a function if IPAddress succeeds, to determine whether an additional + factor is required. + --> + <entry key="authn/Password"> + <bean parent="shibboleth.authn.MFA.Transition" p:nextFlowStrategy-ref="checkSecondFactor" /> + </entry> + + <!-- An implicit final rule will return whatever the final flow returns. --> + </util:map> + + <!-- Example script to see if second factor is required. --> + <bean id="checkSecondFactor" parent="shibboleth.ContextFunctions.Scripted" factory-method="inlineScript" + p:customObject-ref="shibboleth.AttributeResolverService"> + <constructor-arg> + <value> + <![CDATA[ + nextFlow = null; + // Go straight to second factor if we have to, or set up for an attribute lookup first. + authCtx = input.getSubcontext("net.shibboleth.idp.authn.context.AuthenticationContext"); + mfaCtx = authCtx.getSubcontext("net.shibboleth.idp.authn.context.MultiFactorAuthenticationContext"); + if (mfaCtx.isAcceptable()) { + // Attribute check is required to decide if first factor alone is enough. + resCtx = input.getSubcontext( + "net.shibboleth.idp.attribute.resolver.context.AttributeResolutionContext", true); + // Look up the username using a standard function. + usernameLookupStrategyClass + = Java.type("net.shibboleth.idp.session.context.navigate.CanonicalUsernameLookupStrategy"); + usernameLookupStrategy = new usernameLookupStrategyClass(); + resCtx.setPrincipal(usernameLookupStrategy.apply(input)); + resCtx.getRequestedIdPAttributeNames().add("eduPersonEntitlement"); + resCtx.resolveAttributes(custom); + // Check for an attribute that authorizes use of first factor. + attribute = resCtx.getResolvedIdPAttributes().get("eduPersonEntitlement"); + valueType = Java.type("net.shibboleth.idp.attribute.StringAttributeValue"); + if (attribute != null && attribute.getValues().contains(new valueType("http://tier.internet2.edu/mfa/enabled"))) { + nextFlow = "authn/Gaspo"; + } + input.removeSubcontext(resCtx); // cleanup + } + nextFlow; // pass control to second factor or end with the first + ]]> + </value> + </constructor-arg> + </bean> + +</beans> diff --git a/docs/401/examples/401.2.4-athletics-dept.txt b/docs/401/examples/401.2.4-athletics-dept.txt new file mode 100644 index 0000000..27e4405 --- /dev/null +++ b/docs/401/examples/401.2.4-athletics-dept.txt @@ -0,0 +1,15 @@ +ahenderson36 +amorrison42 +bsmith65 +cthompson28 +janderson13 +jdavis4 +jlangenberg100 +jprice108 +jvales117 +ldavis5 +mgrady137 +mmartinez133 +nscott103 +pthompson61 +rdavis16 diff --git a/docs/401/examples/401.2.5-banner-netids.txt b/docs/401/examples/401.2.5-banner-netids.txt new file mode 100644 index 0000000..2362df0 --- /dev/null +++ b/docs/401/examples/401.2.5-banner-netids.txt @@ -0,0 +1,5 @@ +agasper508 +agasper678 +alopez899 +aprice362 +agrady791 diff --git a/docs/401/examples/401.3.2-grouper-loader.properties b/docs/401/examples/401.3.2-grouper-loader.properties new file mode 100644 index 0000000..45f2b18 --- /dev/null +++ b/docs/401/examples/401.3.2-grouper-loader.properties @@ -0,0 +1,118 @@ +#specify the consumers here. specify the consumer name after the changeLog.consumer. part. This example is "psp" +#but it could be changeLog.consumer.myConsumerName.class +#the class must extend edu.internet2.middleware.grouper.changeLog.ChangeLogConsumerBase +#changeLog.consumer.psp.class = edu.internet2.middleware.psp.grouper.PspChangeLogConsumer + +#the quartz cron is a cron-like string. it defaults to every minute on the minute (since the temp to change log job runs +#at 10 seconds to each minute). it defaults to this: 0 * * * * ? +#though it will stagger each one by 2 seconds +# http://www.quartz-scheduler.org/documentation/quartz-1.x/tutorials/crontrigger +#changeLog.consumer.psp.quartzCron = 0 * * * * ? + +# To retry processing a change log entry if an error occurs, set retryOnError to true. Defaults to false. +#changeLog.consumer.psp.retryOnError = false + +# To run full provisioning synchronizations periodically, provide the class name which provides a 'public void fullSync()' method. +#changeLog.psp.fullSync.class = edu.internet2.middleware.psp.grouper.PspChangeLogConsumer + +# Schedule full synchronizations. Defaults to 5 am : 0 0 5 * * ?. +#changeLog.psp.fullSync.quartzCron = 0 0 5 * * ? + +# Run a full synchronization job at startup. Defaults to false. +#changeLog.psp.fullSync.runAtStartup = false + +# Omit diff responses from bulk response to conserve memory. +#changeLog.psp.fullSync.omitDiffResponses = true + +# Omit sync responses from bulk response to conserve memory. +#changeLog.psp.fullSync.omitSyncResponses = true + +################################# +## LDAP connections +################################# +# specify the ldap connection with user, pass, url +# the string after "ldap." is the ID of the connection, and it should not have +# spaces or other special chars in it. In this case is it "personLdap" + +#note the URL should start with ldap: or ldaps: if it is SSL. +#It should contain the server and port (optional if not default), and baseDn, +#e.g. ldaps://ldapserver.school.edu:636/dc=school,dc=edu +ldap.demo.url = ldap://localhost:389/ + +#optional, if authenticated +ldap.demo.user = cn=root,dc=internet2,dc=edu + +#optional, if authenticated note the password can be stored encrypted in an external file +ldap.demo.pass = password + +#optional, if you are using tls, set this to true. Generally you will not be using an SSL URL to use TLS... +ldap.demo.tls = false + +#optional, if using sasl +#ldap.personLdap.saslAuthorizationId = +#ldap.personLdap.saslRealm = + +#optional (note, time limit is for search operations, timeout is for connection timeouts), +#most of these default to vt-ldap defaults. times are in millis +#validateOnCheckout defaults to true if all other validate methods are false +#ldap.personLdap.batchSize = +#ldap.personLdap.countLimit = +#ldap.personLdap.timeLimit = +#ldap.personLdap.timeout = +#ldap.personLdap.minPoolSize = +#ldap.personLdap.maxPoolSize = +#ldap.personLdap.validateOnCheckIn = +#ldap.personLdap.validateOnCheckOut = +#ldap.personLdap.validatePeriodically = +#ldap.personLdap.validateTimerPeriod = +#ldap.personLdap.pruneTimerPeriod = +#if connections expire after a certain amount of time, this is it, in millis, defaults to 300000 (5 minutes) +#ldap.personLdap.expirationTime = + +#make the paths fully qualified and not relative to the loader group. +loader.ldap.requireTopStemAsStemFromConfigGroup=false + +changeLog.consumer.pspng_groupOfNames.class = edu.internet2.middleware.grouper.pspng.PspChangelogConsumerShim +changeLog.consumer.pspng_groupOfNames.type = edu.internet2.middleware.grouper.pspng.LdapGroupProvisioner +changeLog.consumer.pspng_groupOfNames.quartzCron = 0 * * * * ? +changeLog.consumer.pspng_groupOfNames.ldapPoolName = demo +changeLog.consumer.pspng_groupOfNames.supportsEmptyGroups = false +changeLog.consumer.pspng_groupOfNames.memberAttributeName = member +changeLog.consumer.pspng_groupOfNames.memberAttributeValueFormat = ${ldapUser.getDn()} +changeLog.consumer.pspng_groupOfNames.groupSearchBaseDn = ou=groups,dc=internet2,dc=edu +changeLog.consumer.pspng_groupOfNames.allGroupsSearchFilter = objectclass=groupOfNames +changeLog.consumer.pspng_groupOfNames.singleGroupSearchFilter = (&(objectclass=groupOfNames)(cn=${group.name})) +changeLog.consumer.pspng_groupOfNames.groupSearchAttributes = cn,objectclass +changeLog.consumer.pspng_groupOfNames.groupCreationLdifTemplate = dn: cn=${group.name}||cn: ${group.name}||objectclass: groupOfNames +changeLog.consumer.pspng_groupOfNames.userSearchBaseDn = ou=people,dc=internet2,dc=edu +changeLog.consumer.pspng_groupOfNames.userSearchFilter = uid=${subject.id} +changeLog.consumer.pspng_groupOfNames.grouperIsAuthoritative = false + + +changeLog.consumer.pspng_entitlements.class = edu.internet2.middleware.grouper.pspng.PspChangelogConsumerShim +changeLog.consumer.pspng_entitlements.type = edu.internet2.middleware.grouper.pspng.LdapAttributeProvisioner +changeLog.consumer.pspng_entitlements.quartzCron = 0 * * * * ? +changeLog.consumer.pspng_entitlements.ldapPoolName = demo +changeLog.consumer.pspng_entitlements.provisionedAttributeName = eduPersonEntitlement +changeLog.consumer.pspng_entitlements.provisionedAttributeValueFormat = ${group.name.equalsIgnoreCase('app:mfa:mfa_enabled') ? 'http://tier.internet2.edu/mfa/enabled' : (group.name.equalsIgnoreCase('app:boardeffect:boardeffect_authorized') ? 'https://college.boardeffect.com/' : 'urn:mace:example.edu:' + group.extension) } +changeLog.consumer.pspng_entitlements.userSearchBaseDn = ou=people,dc=internet2,dc=edu +changeLog.consumer.pspng_entitlements.userSearchFilter = uid=${subject.id} +changeLog.consumer.pspng_entitlements.allProvisionedValuesPrefix=* + +##################################### +## Messaging integration with change log +##################################### +changeLog.consumer.rabbitMqMessagingSample.quartzCron = 0 * * * * ? + +# note, change "messagingSample" in key to be the name of the consumer. e.g. changeLog.consumer.someNameAnyName.class +changeLog.consumer.rabbitMqMessagingSample.class = edu.internet2.middleware.grouper.changeLog.esb.consumer.EsbConsumer + +changeLog.consumer.rabbitMqMessagingSample.publisher.class = edu.internet2.middleware.grouper.changeLog.esb.consumer.EsbMessagingPublisher +changeLog.consumer.rabbitMqMessagingSample.publisher.messagingSystemName = rabbitmq +# note, routingKey property is valid only for rabbitmq. For other messaging systems, it is ignored. +changeLog.consumer.rabbitMqMessagingSample.publisher.routingKey = +## queue or topic +changeLog.consumer.rabbitMqMessagingSample.publisher.messageQueueType = queue +changeLog.consumer.rabbitMqMessagingSample.publisher.queueOrTopicName = grouper +## this is optional if not using "id" for subjectId, need to be a subject attribute in the sources.xml +#changeLog.consumer.rabbitMqMessagingSample.publisher.addSubjectAttributes = email diff --git a/docs/401/examples/401.3.2-grouper.client.properties b/docs/401/examples/401.3.2-grouper.client.properties new file mode 100644 index 0000000..8edc9a9 --- /dev/null +++ b/docs/401/examples/401.3.2-grouper.client.properties @@ -0,0 +1,112 @@ +# +# Copyright 2014 Internet2 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# +# Grouper client configuration +# $Id: grouper.client.example.properties,v 1.24 2009-12-30 04:23:02 mchyzer Exp $ +# + +# The grouper client uses Grouper Configuration Overlays (documented on wiki) +# By default the configuration is read from grouper.client.base.properties +# (which should not be edited), and the grouper.client.properties overlays +# the base settings. See the grouper.client.base.properties for the possible +# settings that can be applied to the grouper.client.properties + +######################################## +## LDAP connection settings +######################################## + +# url of directory, including the base DN (distinguished name) +# e.g. ldap://server.school.edu/dc=school,dc=edu +# e.g. ldaps://server.school.edu/dc=school,dc=edu +grouperClient.ldap.url = + +# kerberos principal used to connect to ldap +grouperClient.ldap.login = + +# password for shared secret authentication to ldap +# or you can put a filename with an encrypted password +grouperClient.ldap.password = + +######################################## +## Web service Connection settings +######################################## + +# url of web service, should include everything up to the first resource to access +# e.g. http://groups.school.edu:8090/grouper-ws/servicesRest +# e.g. https://groups.school.edu/grouper-ws/servicesRest +grouperClient.webService.url = https://localhost/grouper-ws/servicesRest + +# kerberos principal used to connect to web service +grouperClient.webService.login = banderson + +# password for shared secret authentication to web service +# or you can put a filename with an encrypted password +grouperClient.webService.password.elConfig = password + + +################################ +## Grouper Messaging System +################################ + +# name of messaging system which is the default +grouper.messaging.default.name.of.messaging.system = rabbitmq + +# name of a messaging system. note, "grouperBuiltinMessaging" can be arbitrary +# grouper.messaging.system.grouperBuiltinMessaging.name = grouperBuiltinMessaging + +# class that implements edu.internet2.middleware.grouperClient.messaging.GrouperMessagingSystem +# grouper.messaging.system.grouperBuiltinMessaging.class = edu.internet2.middleware.grouper.messaging.GrouperBuiltinMessagingSystem + +# name of a messaging system. note, "grouperBuiltinMessaging" can be arbitrary +grouper.messaging.system.rabbitmqSystem.name = rabbitmqSystem + +# class that implements edu.internet2.middleware.grouperClient.messaging.GrouperMessagingSystem +grouper.messaging.system.rabbitmqSystem.class = edu.internet2.middleware.grouperMessagingRabbitmq.GrouperMessagingRabbitmqSystem + +# host address of rabbitmq queue +grouper.messaging.system.rabbitmqSystem.host = rabbitmq + +# virtual host of rabbitmq queue +grouper.messaging.system.rabbitmqSystem.virtualhost = + +# port of rabbitmq queue +grouper.messaging.system.rabbitmqSystem.port = + +grouper.messaging.system.rabbitmqSystem.defaultPageSize = 10 + +grouper.messaging.system.rabbitmqSystem.maxPageSize = 50 + + +# name of a messaging system, required +grouper.messaging.system.rabbitmq.name = rabbitmq + +# default system settings to this messaging system, note, there is only one level of inheritance +grouper.messaging.system.rabbitmq.defaultSystemName = rabbitmqSystem + +grouper.messaging.system.rabbitmq.user = guest + +#pass +grouper.messaging.system.rabbitmq.password.elConfig = guest +# set the following three properties if you want to use TLS connection to rabbitmq. All three need to be populated. +# TLS Version +#grouper.messaging.system.rabbitmqSystem.tlsVersion = TLSv1.1 + +# path to trust store file +#grouper.messaging.system.rabbitmqSystem.pathToTrustStore = + +# trust passphrase +#grouper.messaging.system.rabbitmqSystem.trustPassphrase = diff --git a/docs/401/index.rst b/docs/401/index.rst new file mode 100644 index 0000000..59cd18e --- /dev/null +++ b/docs/401/index.rst @@ -0,0 +1,22 @@ +Access Goverance Practicum (401) +================================ + +The practicum consists of four labs where students can apply the knowledge they +have learned from previous Grouper courses. Students can demostrate how to +implement access goverance using Grouper and associated `InCommon Trusted +Access Platform`_ components by translating natural language policy into the +appropriate digital policy. The access governance practicum incorporates much +of the InCommon Trusted Access Platform and provides a “full IAM stack” +experience. + +.. toctree:: + :maxdepth: 2 + + 401.1 + 401.2 + 401.3 + 401.4 + 401.4-example-solution + appendix + +.. _InCommon Trusted Access Platform: https://www.incommon.org/tap/ diff --git a/docs/401/intro.rst b/docs/401/intro.rst new file mode 100644 index 0000000..aeeef28 --- /dev/null +++ b/docs/401/intro.rst @@ -0,0 +1,18 @@ +============ +Introduction +============ + +The TIER Access Governance Practicum (401) describes a series of real world +access governance use cases that students can use to demonstrate knowledge +of how to translate natural language policy into the appropriate digital +policy in Grouper. The access governance practicum incorporates much of the +TIER IAM suite of components and provides a “full TIER stack” experience. + +The Practicum consists of 4 labs that will allow students to apply knowledge +they have learned from other Grouper courses. They will present real-world +access control scenarios. Instructors will present techniques and possible +solutions to these problems. + + + + diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..298ea9e --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,19 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..a52be6a --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,182 @@ +# -*- coding: utf-8 -*- +# +# Configuration file for the Sphinx documentation builder. +# +# This file does only contain a selection of the most common options. For a +# full list see the documentation: +# http://www.sphinx-doc.org/en/master/config + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +# import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) + + +# -- Project information ----------------------------------------------------- + +project = 'Grouper Training Environment' +copyright = '2019, Internet2' +html_show_copyright = True +author = 'Carl Waldbieser' + +# The short X.Y version +version = '' +# The full version, including alpha/beta/rc tags +release = '062019' + + +# -- General configuration --------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = None + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +#html_theme = 'agogo' +#html_theme = 'alabaster' +#html_theme = 'bizstyle' +#html_theme = 'classic' +html_theme = 'haiku' +#html_theme = 'nature' +#html_theme = 'pyramid' +#html_theme = 'scrolls' +#html_theme = 'traditional' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +# html_static_path = ['_static'] + +# Custom sidebar templates, must be a dictionary that maps document names +# to template names. +# +# The default sidebars (for documents that don't match any pattern) are +# defined by theme itself. Builtin themes are using these templates by +# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', +# 'searchbox.html']``. +# +# html_sidebars = {} + + +# -- Options for HTMLHelp output --------------------------------------------- + +# Output file base name for HTML help builder. +htmlhelp_basename = 'gte-doc' + + +# -- Options for LaTeX output ------------------------------------------------ + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'gte-doc.tex', 'Grouper Training Environment Documentation', + 'Carl Waldbieser', 'manual'), +] + + +# -- Options for manual page output ------------------------------------------ + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'gte-doc', 'Grouper Training Environment Documentation', + [author], 1) +] + + +# -- Options for Texinfo output ---------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'gte-doc', 'Grouper Training Environment Documentation', + author, 'gte-doc', 'One line description of project.', + 'Miscellaneous'), +] + + +# -- Options for Epub output ------------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = project + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +# +# epub_identifier = '' + +# A unique identification for the text. +# +# epub_uid = '' + +# A list of files that should not be packed into the epub file. +epub_exclude_files = ['search.html'] diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..bae9535 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,25 @@ +Grouper Training Environment Documentation +========================================== + +.. toctree:: + :maxdepth: 2 + + 201/index + 401/index + +Conventions +=========== + +In the documentation, many references will be made to Grouper groups and +folders. These references will sometimes take the form of a complete path to +the referenced object, such as `:app:vpn:service:ref:ad_hoc`. Other times, the +references will be relative to the current context under discussion. For +example, when referring to the same application-specific reference group for +the VPN service, the notation `...:ref:ad_hoc` may be used to indicate that a +portion of the full path has been omitted. + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`search` diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..27f573b --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% + +:end +popd