- Created by chris.hyzer.3@at.internet2.edu, last modified about an hour ago
Penn front door authorization as presented in the June 2025 InCommon IAM Online.
Summary
See this marketing video to explain front door authorization.
Shibboleth SAML Service Providers (SP's) can have a front door authorization policy assigned which will ensure that users are eligible for the service.
When a user is not allowed to access an application (SP), they are sent an error page (could be customized or an external link) instead of the application.
There are currently a dozen coarse-grained options for the eligibility population (described below). A policy group could be used instead of or in addition.
Application admins can self-manage their front-door configuration.
This is an extra security control on top of whatever specific authorization a service performs. You can think of it like a security guard at the front of a building. Applications still need to provide the same authorization, but deprovisioning is not as urgent.
Frequently asked questions
- If my application is protected by Workforce, and someone is being blocked, how do I remedy that?
- If the user is working at Penn, they should have an affiliation which reflects that relationship. Assuming they are not paid by Penn, their sponsor should give them a contractor or research affiliation.
- If the user is not working at Penn, then perhaps the Workforce coarse grained reference group is not appropriate for this service and the front door for this service should be reconfigured to use something wider (e.g. Member which includes students and related organizations like the children's hospital).
- Does this affect local log ins?
- If a user is authenticating and is not using Shibboleth, (i.e. a local password), then the front door is not used
- Note: your application should not allow local logins by policy. You might have a local login extraordinary situations (e.g. for super admins who need to reconfigure SSO).
- How will this affect the user experience?
- The user will not know the front door is being used, unless they leave Penn or their reference/policy group
- Do I have to provide a list of at least two admins or owners?
- No, you can let the IT dept manage the front door if you do not have the technical staff to manage it
User flow
- User attempts to log in to an application
- Shibboleth determines which population is eligible for that service based on how it is configured. The membership of that PennGroup (eligible population) is checked for the user (i.e. are they eligible)
- If the user is in the population, the user is sent to the service.
- The service has more specific authorization checks and the user might be able to use the application or see an application error page
- If the user is not in the population, the user will be sent to a generic error handler at Grouper
- If the service does not have any Grouper error handling configured, the user will go to a generic error page
- The error page could be hosted by the service owner at some location (not on the service that is protected)
- The error page in Grouper could be customized to provide specific information to the user
- To tell the user whom to contact for support
- To clearly communicate the access requirements
Coarse-grained eligibility populations
Note: “Requires Two-step” means all users must be enrolled in Duo.
If the application selects a reference group for the eligibility requirement, they can pick: Workforce, Workforce in Two-Step, Member, Member in Two-step, etc.
Error page - generic
This is a dynamic page that will attempt to reduce tickets based on the state of the user.
- If the service has no eligibility, then users will never see the error page.
- If the service has only a reference group eligibility, then if the user is not in that group then they will see this page. If the reference group requires Two-step then the user must be enrolled (not bypassed) in Two-Step.
- If the service has only a policy group eligibility, then if the user is not in that group then they will see this page. If the policy group requires Two-step (via composite) then the user must be enrolled (not bypassed) in Two-Step. It is easier to add a reference group that requires Two-step.
- If the service has both a reference group and a policy group then the user must be in both groups. If the reference group requires Two-step then the user must be enrolled (not bypassed) in Two-Step.
Basic page:
Two step error:
Timing error:
Generic error page - custom UI
See examples of screen above
grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.0.enabled = true grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.0.label = Entity ID grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.0.order = 10 grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.0.userQueryType = url grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.0.variableToAssign = cu_var grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.0.variableType = string grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.1.bindVar0 = cu_var grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.1.bindVar0Type = string grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.1.configId = grouper grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.1.enabled = true grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.1.label = SP name grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.1.order = 20 grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.1.query = select name from sso_prod_entity_front_door where entity_id = ? grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.1.userQueryType = sql grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.1.variableToAssign = cu_spName grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.1.variableType = string grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.10.bindVar0 = \u0024{subject.id} grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.10.bindVar0Type = string grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.10.configId = grouper grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.10.enabled = true grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.10.label = Has been in workforce grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.10.order = 110 grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.10.query = select case when exists (select 1 from penn_custom_ui_mships_v where group_name = 'penn\u003Acommunity\u003AemployeeOrContractorIncludingUphs' and subject_id = ? and subject_source_id in ('pennperson') and has_been_in_group = 'T') then 1 else 0 end as has_been_in_group grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.10.userQueryType = sql grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.10.variableToAssign = cu_hasBeenInWorkforceGroup grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.10.variableType = boolean grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.11.bindVar0 = \u0024{subject.id} grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.11.bindVar0Type = string grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.11.configId = grouper grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.11.enabled = true grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.11.label = Workforce membership ended minutes ago grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.11.order = 120 grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.11.query = select coalesce(minutes_since_in_group, 99999999) as min_since_in_group from (select ((extract(epoch from now()) - user_end_secs_since_1970)/60)\u003A\u003Anumeric\u003A\u003Ainteger as minutes_since_in_group from penn_custom_ui_mships_v where group_name = 'penn\u003Acommunity\u003AemployeeOrContractorIncludingUphs' and subject_id = ? and user_end_secs_since_1970 is not null and subject_source_id in ('pennperson') limit 1) as minutes_since_in_group_table grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.11.userQueryType = sql grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.11.variableToAssign = cu_workforceEndedMinutesAgo grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.11.variableType = integer grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.12.bindVar0 = cu_var grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.12.bindVar0Type = string grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.12.configId = grouper grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.12.enabled = true grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.12.label = Requires two-step grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.12.order = 35 grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.12.query = select case when exists (select 1 from sso_prod_entity_front_door where entity_id = ? and requires_twostep = 'T') then 1 else 0 end as requires_twostep_integer grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.12.userQueryType = sql grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.12.variableToAssign = cu_requiresTwostep grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.12.variableType = boolean grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.13.bindVar0 = cu_var grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.13.bindVar0Type = string grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.13.configId = grouper grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.13.label = Error page type grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.13.order = 140 grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.13.query = select error_page_type from sso_prod_entity_front_door where entity_id = ? grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.13.userQueryType = sql grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.13.variableToAssign = cu_errorPageType grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.14.bindVar0 = cu_var grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.14.bindVar0Type = string grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.14.configId = grouper grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.14.label = Error page URL grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.14.order = 150 grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.14.query = select error_page_url from sso_prod_entity_front_door where entity_id = ? grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.14.userQueryType = sql grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.14.variableToAssign = cu_errorPageUrl grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.15.bindVar0 = cu_var grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.15.bindVar0Type = string grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.15.configId = grouper grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.15.label = Error page text grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.15.order = 160 grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.15.query = select error_page_text || '<br /><br />' from sso_prod_entity_front_door where entity_id = ? grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.15.userQueryType = sql grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.15.variableToAssign = cu_errorPageText grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.2.enabled = true grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.2.label = SP found grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.2.order = 30 grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.2.script = \u0024{!grouperUtil.isBlank(cu_var) && !grouperUtil.isBlank(cu_spName)} grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.2.userQueryType = expressionLanguage grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.2.variableToAssign = cu_spFound grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.2.variableType = boolean grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.3.bindVar0 = cu_var grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.3.bindVar0Type = string grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.3.configId = grouper grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.3.enabled = true grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.3.label = Eligibility group grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.3.order = 40 grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.3.query = select group_name from sso_prod_entity_groups_v where entity_id = ? grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.3.userQueryType = sql grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.3.variableToAssign = cu_frontDoorPolicyGroup grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.3.variableType = string grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.4.bindVar0 = cu_var grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.4.bindVar0Type = string grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.4.bindVar1 = \u0024{subject.id} grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.4.bindVar1Type = string grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.4.configId = grouper grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.4.enabled = true grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.4.label = In eligibility group grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.4.order = 50 grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.4.query = select is_in_group from sso_prod_entity_mships2_v where entity_id = ? and subject_id = ? grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.4.userQueryType = sql grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.4.variableToAssign = cu_inEligibilityGroup grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.4.variableType = boolean grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.5.bindVar0 = cu_var grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.5.bindVar0Type = string grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.5.bindVar1 = \u0024{subject.id} grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.5.bindVar1Type = string grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.5.configId = grouper grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.5.enabled = true grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.5.label = Has been in eligibility group grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.5.order = 60 grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.5.query = select has_been_in_group from sso_prod_entity_mships2_v where entity_id = ? and subject_id = ? grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.5.userQueryType = sql grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.5.variableToAssign = cu_hasBeenInEligibilityGroup grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.5.variableType = boolean grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.6.bindVar0 = cu_var grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.6.bindVar0Type = string grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.6.bindVar1 = \u0024{subject.id} grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.6.bindVar1Type = string grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.6.configId = grouper grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.6.enabled = true grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.6.label = Group membership ended minutes ago grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.6.order = 70 grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.6.query = select min_since_in_group from sso_prod_entity_mships2_v where entity_id = ? and subject_id = ? grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.6.userQueryType = sql grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.6.variableToAssign = cu_groupMembershipEndedMinutesAgo grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.6.variableType = integer grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.7.bindVar0 = cu_var grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.7.bindVar0Type = string grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.7.bindVar1 = \u0024{subject.id} grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.7.bindVar1Type = string grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.7.configId = grouper grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.7.enabled = true grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.7.label = Has been in group for minutes grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.7.order = 80 grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.7.query = select min_been_in_group from sso_prod_entity_mships2_v where entity_id = ? and subject_id = ? grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.7.userQueryType = sql grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.7.variableToAssign = cu_beenInGroupForMinutes grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.7.variableType = integer grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.8.bindVar0 = \u0024{subject.id} grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.8.bindVar0Type = string grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.8.configId = grouper grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.8.enabled = true grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.8.label = In two step group grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.8.order = 90 grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.8.query = select case when exists (select 1 from penn_custom_ui_mships_v where group_name = 'penn\u003Acommunity\u003Aauthentication\u003AtwoStepUsers' and subject_id = ? and subject_source_id in ('pennperson') and is_user = 'T') then 1 else 0 end as is_user grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.8.userQueryType = sql grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.8.variableToAssign = cu_inTwoStepGroup grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.8.variableType = boolean grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.9.bindVar0 = \u0024{subject.id} grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.9.bindVar0Type = string grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.9.configId = grouper grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.9.enabled = true grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.9.label = Has been in two-step group for minutes grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.9.order = 100 grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.9.query = select minutes_been_in_group as min_been_in_group from (select ((extract(epoch from now()) - user_start_secs_since_1970)/60)\u003A\u003Anumeric\u003A\u003Ainteger as minutes_been_in_group from penn_custom_ui_mships_v where group_name = 'penn\u003Acommunity\u003Aauthentication\u003AtwoStepUsers' and subject_id = ? and user_start_secs_since_1970 is not null and subject_source_id in ('pennperson') limit 1) as minutes_been_in_group_table grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.9.userQueryType = sql grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.9.variableToAssign = cu_beenInTwoStepGroupForMinutes grouperCustomUI.webLoginFrontDoorErrorPageProd.cuQuery.9.variableType = integer grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.0.defaultText = true grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.0.enabled = true grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.0.endIfMatches = true grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.0.index = 10 grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.0.text = <h1>Penn WebLogin - not authorized</h1> grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.0.textType = header grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.1.defaultText = true grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.1.enabled = true grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.1.endIfMatches = true grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.1.index = 10 grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.1.text = grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.1.textType = helpLink grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.10.enabled = true grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.10.endIfMatches = true grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.10.index = -100 grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.10.script = \u0024{cu_errorPageType == 'other_url' } grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.10.text = \u0024{cu_errorPageUrl} grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.10.textType = redirectToUrl grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.2.defaultText = true grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.2.enabled = true grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.2.index = 10 grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.2.textBoolean = false grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.2.textType = enrollButtonShow grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.3.endIfMatches = true grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.3.index = 0 grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.3.text = Find a person to see their error page grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.3.textType = managerInstructions grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.4.enabled = true grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.4.endIfMatches = true grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.4.index = 10 grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.4.script = \u0024{grouperUtil.isBlank(cu_var) || grouperUtil.isBlank(cu_spName)} grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.4.text = The specifics of the error is unknown. You are not allowed to access the application. Discuss your status with your university manager or sponsor. grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.4.textType = enrollmentLabel grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.5.enabled = true grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.5.endIfMatches = true grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.5.index = 20 grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.5.script = \u0024{cu_spFound && cu_inEligibilityGroup && cu_beenInGroupForMinutes > 30 && (!cu_requiresTwostep || (cu_inTwoStepGroup && cu_beenInTwoStepGroupForMinutes > 30)) } grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.5.text = You are allowed to access the application\u003A \u0024{grouperUtil.defaultString(cu_spName)}. You should not be experiencing an error. Wait some time and try again or open a ticket to resolve the issue. grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.5.textType = enrollmentLabel grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.6.enabled = true grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.6.endIfMatches = true grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.6.index = 30 grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.6.script = \u0024{cu_spFound && cu_inEligibilityGroup && (!cu_requiresTwostep || (cu_inTwoStepGroup )) } grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.6.text = You are allowed to access the application\u003A \u0024{grouperUtil.defaultString(cu_spName)}. Since your access has been granted recently, and it takes thirty minutes for the access to be enabled, please try again shortly. grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.6.textType = enrollmentLabel grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.7.enabled = true grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.7.index = 40 grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.7.script = \u0024{cu_spFound && cu_requiresTwostep & !cu_inTwoStepGroup } grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.7.text = <font style="color\u003Abrown"><b>Error\u003A</b></font> You must enroll in <a href="https\u003A//www.isc.upenn.edu/how-to/two-step-verification-getting-started">Two-Step Verification</a><br /> grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.7.textType = enrollmentLabel grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.8.enabled = true grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.8.index = 50 grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.8.script = \u0024{cu_spFound && !cu_inEligibilityGroup} grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.8.text = <font style="color\u003Abrown"><b>Error\u003A</b></font> You are not authorized to access the application\u003A \u0024{grouperUtil.defaultString(cu_spName, "")}. Discuss your status with your university manager or sponsor.<br /> grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.8.textType = enrollmentLabel grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.9.enabled = true grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.9.index = -10 grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.9.script = \u0024{cu_errorPageType == 'customized'} grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.9.text = \u0024{cu_errorPageText} grouperCustomUI.webLoginFrontDoorErrorPageProd.cuTextConfig.9.textType = enrollmentLabel grouperCustomUI.webLoginFrontDoorErrorPageProd.groupCanAssignVariables = penn\u003Aisc\u003Ats\u003Aiam\u003Aweblogin\u003Aservice\u003Apolicy\u003AidpFrontDoorProd\u003Asecurity\u003AidpFrontDoorProdCustomUIAdmins grouperCustomUI.webLoginFrontDoorErrorPageProd.groupCanSeeScreenState = penn\u003Aisc\u003Ats\u003Aiam\u003Aweblogin\u003Aservice\u003Apolicy\u003AidpFrontDoorProd\u003Asecurity\u003AidpFrontDoorProdCustomUIAdmins grouperCustomUI.webLoginFrontDoorErrorPageProd.groupCanSeeUserEnvironment = penn\u003Aisc\u003Ats\u003Aiam\u003Aweblogin\u003Aservice\u003Apolicy\u003AidpFrontDoorProd\u003Asecurity\u003AidpFrontDoorProdCustomUIAdmins grouperCustomUI.webLoginFrontDoorErrorPageProd.groupOfManagers = penn\u003Aisc\u003Ats\u003Aiam\u003Aweblogin\u003Aservice\u003Apolicy\u003AidpFrontDoorProd\u003Asecurity\u003AidpFrontDoorProdCustomUIAdmins grouperCustomUI.webLoginFrontDoorErrorPageProd.groupUUIDOrName = penn\u003Aisc\u003Ats\u003Aiam\u003Aweblogin\u003Aservice\u003Apolicy\u003AidpFrontDoorProd\u003Aservice\u003Aref\u003AidpFrontDoorProdErrorPage grouperCustomUI.webLoginFrontDoorErrorPageProd.numberOfQueries = 16 grouperCustomUI.webLoginFrontDoorErrorPageProd.numberOfTextConfigs = 11
Error page - custom
This error page has custom HTML embedded. Note all the dynamic features of the generic page exist in the custom page, and it has additional static HTML information as configured.
Feed from splunk to Grouper about log ins to service providers
There is a table for entity id's
There is a table of login logs from splunk
This is populated by GSH daemon which runs every ten minutes
import java.sql.Timestamp; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TimeZone; import org.apache.commons.lang.StringUtils; import com.fasterxml.jackson.databind.JsonNode; import edu.internet2.middleware.grouper.GrouperSession; import edu.internet2.middleware.grouper.Member; import edu.internet2.middleware.grouper.MemberFinder; import edu.internet2.middleware.grouper.SubjectFinder; import edu.internet2.middleware.grouper.app.loader.GrouperLoaderConfig; import edu.internet2.middleware.grouper.app.loader.OtherJobScript; import edu.internet2.middleware.grouper.misc.GrouperStartup; import edu.internet2.middleware.grouper.util.GrouperHttpClient; import edu.internet2.middleware.grouper.util.GrouperHttpMethod; import edu.internet2.middleware.grouper.util.GrouperUtil; import edu.internet2.middleware.grouperClient.jdbc.GcDbAccess; import edu.internet2.middleware.grouperClient.util.GrouperClientUtils; import edu.internet2.middleware.subject.Subject; //public class Test79splunkSpLogins { public static Set<Long> memberIdIndexInGroup(String groupName, Collection<Long> memberIdIndexesCollection) { int theBatchSize = 1000; List<Long> memberIdIndexesList = new ArrayList<>(GrouperUtil.nonNull(memberIdIndexesCollection)); int theNumberOfBatches = GrouperUtil.batchNumberOfBatches(memberIdIndexesList, theBatchSize, false); Set<Long> resultMemberIdIndexes = new HashSet<>(); // go through in batches for (int i=0;i<theNumberOfBatches;i++) { List<Long> memberIdIndexesBatch = GrouperUtil.batchList(memberIdIndexesList, theBatchSize, i); List<Long> memberIdIndexesExist = new GcDbAccess().connectionName("awsProdReadonly").sql( "select gm.id_index from grouper_memberships_lw_v gmlv, grouper_members gm where " + " gm.id = gmlv.member_id and gmlv.list_name = 'members' " + " and gmlv.group_name = ? and gm.id_index in (" + GrouperClientUtils.appendQuestions(memberIdIndexesBatch.size()) + ")"). addBindVar(groupName).addBindVars(memberIdIndexesBatch).selectList(Long.class); resultMemberIdIndexes.addAll(memberIdIndexesExist); } return resultMemberIdIndexes; } // public static void main(String[] args) { GrouperStartup.startup(); GrouperSession grouperSession = GrouperSession.startRootSession(); Map<String, Object> debugMap = new LinkedHashMap<>(); String splunkBaseUrl = GrouperUtil.stripLastSlashIfExists(GrouperLoaderConfig.retrieveConfig().propertyValueStringRequired("splunk.url")); String splunkBearerToken = GrouperLoaderConfig.retrieveConfig().propertyValueStringRequired("splunk.bearerTokenSecret"); long startedMillis = System.currentTimeMillis(); // https://sls.isc.upenn.edu:8089/servicesNS/-/upenn_isc_attribution/search/jobs/export?search=search%20%60sso_authentications%60&exec_mode=oneshot&output_mode=json GrouperHttpClient grouperHttpClient = new GrouperHttpClient(). assignGrouperHttpMethod(GrouperHttpMethod.get). addHeader("Content-Type", "application/json"). addHeader("Accept", "application/json"). addHeader("Authorization", "Bearer " + splunkBearerToken). assignUrl(splunkBaseUrl + "/servicesNS/-/upenn_isc_attribution/search/jobs/export"). addUrlParameter("search", "search `sso_authentications`"). addUrlParameter("output_mode", "json"). addUrlParameter("exec_mode", "oneshot"). executeRequest(); int responseCode = grouperHttpClient.getResponseCode(); String body = grouperHttpClient.getResponseBody(); if (responseCode != 200) { debugMap.put("splunkResponseCode", responseCode); throw new RuntimeException(responseCode + "," + body); } debugMap.put("splunkQueryTookMs", System.currentTimeMillis() - startedMillis); // {"preview":false,"offset":37239,"result":{"_time":"2024-01-25 11:08:31.132 EST","user":"aaravrr","dest_app":"courses.upenn.edu/sam_rMReby8Vl3M1BiyVWMAT"}} // {"preview":false,"offset":37252,"result":{"_time":"2024-01-25 11:08:28.546 EST","user":"baronche","dest_app":"https://cluster-prod.apps.upenn.edu/shibboleth"}} String[] bodyLines = new String[0]; if (!StringUtils.isBlank(body)) { bodyLines = GrouperUtil.splitTrim(body, "\n"); } int linesTotal = bodyLines.length; debugMap.put("linesTotal", linesTotal); int linesDontMatch = 0; int invalidDates = 0; int invalidUsers = 0; Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("America/New_York")); Set<String> pennkeys = new HashSet<String>(); Set<String> pennids = new HashSet<String>(); Set<String> entityIds = new HashSet<String>(); Timestamp minTimestamp = null; List<Object[]> timeUserSps = new ArrayList<Object[]>(); Timestamp maxTimestampAlreadyLogged = new GcDbAccess().sql("select max(login_timestamp) from sso_prod_logs_person_sp").select(Timestamp.class); if (maxTimestampAlreadyLogged == null) { maxTimestampAlreadyLogged = new Timestamp(0L); } int recordsAlreadyLogged = 0; Map<String, Set<String>> entityIdToPennkeyOrPennid = new HashMap<>(); for (String bodyLine : bodyLines) { if (StringUtils.isBlank(bodyLine)) { continue; } JsonNode mainNode = GrouperUtil.jsonJacksonNode(bodyLine); JsonNode resultNode = mainNode == null ? null : GrouperUtil.jsonJacksonGetNode(mainNode, "result"); String time = resultNode == null ? null : GrouperUtil.jsonJacksonGetString(resultNode, "_time"); String user = resultNode == null ? null : GrouperUtil.jsonJacksonGetString(resultNode, "user"); String dest_app = resultNode == null ? null : GrouperUtil.jsonJacksonGetString(resultNode, "dest_app"); String timeSuffix1 = " EST"; String timeSuffix2 = " EDT"; if (StringUtils.isBlank(time) || StringUtils.isBlank(user) || StringUtils.isBlank(dest_app) || (!time.endsWith(timeSuffix1) && !time.endsWith(timeSuffix2))) { if (linesDontMatch < 10) { debugMap.put("linesDontMatchExample_" + linesDontMatch, bodyLine); } linesDontMatch++; continue; } time = time.substring(0, time.length() - timeSuffix1.length()); SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS"); df.setTimeZone(cal.getTimeZone()); Timestamp timestamp = null; try { Date date = null; date = df.parse(time); timestamp = new Timestamp(date.getTime()); } catch (Exception e) { if (invalidDates < 10) { debugMap.put("invalidDatesExample_" + invalidDates, time); } invalidDates++; } if (timestamp.before(maxTimestampAlreadyLogged)) { recordsAlreadyLogged++; continue; } if (!user.matches("[a-z0-9]{2,8}")) { if (invalidUsers < 10) { debugMap.put("invalidUser_" + invalidUsers, user); } if (OtherJobScript.retrieveFromThreadLocal() == null) { System.out.println("Invalid user: " + user); } invalidUsers++; } if (user.matches("[0-9]{2,8}")) { pennids.add(user); } else { pennkeys.add(user); } entityIds.add(dest_app); if (minTimestamp == null || timestamp.before(minTimestamp)) { minTimestamp = timestamp; } timeUserSps.add(GrouperUtil.toArrayObject(timestamp, user, dest_app)); Set<String> pennkeyOrPennids = entityIdToPennkeyOrPennid.get(dest_app); if (pennkeyOrPennids == null) { pennkeyOrPennids = new HashSet<>(); entityIdToPennkeyOrPennid.put(dest_app, pennkeyOrPennids); } pennkeyOrPennids.add(user); } if (OtherJobScript.retrieveFromThreadLocal() != null) { OtherJobScript.retrieveFromThreadLocal().getOtherJobInput().getHib3GrouperLoaderLog().setTotalCount(bodyLines.length); } debugMap.put("pennkeysCount", pennkeys.size()); debugMap.put("pennidsCount", pennids.size()); debugMap.put("recordsAlreadyLogged", recordsAlreadyLogged); debugMap.put("linesDontMatch", linesDontMatch); debugMap.put("invalidUsers", invalidUsers); debugMap.put("matchedLinesTotal", timeUserSps.size()); Map<String, Long> loginIdToIdIndex = new HashMap<String, Long>(); Map<String, String> loginIdToPennid = new HashMap<String, String>(); // retrieve / create users List<String> pennkeyList = new ArrayList<String>(pennkeys); int batchSize = 1000; int numberOfBatches = GrouperUtil.batchNumberOfBatches(pennkeyList.size(), batchSize, false); int membersCreated = 0; int subjectsNotFound = 0; for (int i=0;i<numberOfBatches;i++) { List<String> batchPennkeys = GrouperUtil.batchList(pennkeyList, batchSize, i); Set<String> batchPennkeysSet = new HashSet<String>(batchPennkeys); String sql = """ select gm.subject_identifier0 AS pennkey, id_index, subject_id from grouper_members gm """ + " where subject_identifier0 in (" + GrouperClientUtils.appendQuestions(batchPennkeys.size()) + ")"; GcDbAccess gcDbAccess = new GcDbAccess().sql(sql).connectionName("awsProdReadonly"); for (String pennkey : batchPennkeys) { gcDbAccess.addBindVar(pennkey); } List<Object[]> subjectIdentifierIdIndexes = gcDbAccess.selectList(Object[].class); for (Object[] subjectIdentifierIdIndex : subjectIdentifierIdIndexes) { String subjectIdentifier = (String)subjectIdentifierIdIndex[0]; Long idIndex = GrouperUtil.longValue(subjectIdentifierIdIndex[1]); batchPennkeysSet.remove(subjectIdentifier); loginIdToIdIndex.put(subjectIdentifier, idIndex); String pennId = (String)subjectIdentifierIdIndex[2]; loginIdToPennid.put(subjectIdentifier, pennId); } for (String pennkey : batchPennkeysSet) { Subject subject = SubjectFinder.findByIdentifierAndSource(pennkey, "pennperson", false); if (subject == null) { if (subjectsNotFound < 10) { debugMap.put("subjectNotFound_" + subjectsNotFound, pennkey); } subjectsNotFound++; continue; } loginIdToPennid.put(pennkey, subject.getId()); Member member = MemberFinder.findBySubject(grouperSession, subject, true); if (OtherJobScript.retrieveFromThreadLocal() != null) { OtherJobScript.retrieveFromThreadLocal().getOtherJobInput().getHib3GrouperLoaderLog().addInsertCount(1); } loginIdToIdIndex.put(pennkey, member.getIdIndex()); if (membersCreated < 10) { debugMap.put("memberCreated_" + membersCreated, pennkey); } membersCreated++; } } List<String> pennidList = new ArrayList<String>(pennids); numberOfBatches = GrouperUtil.batchNumberOfBatches(pennidList.size(), batchSize, false); int membersPennIdCreated = 0; int subjectsPennIdNotFound = 0; for (int i=0;i<numberOfBatches;i++) { List<String> batchPennids = GrouperUtil.batchList(pennidList, batchSize, i); Set<String> batchPennidsSet = new HashSet<String>(batchPennids); String sql = """ select gm.subject_id AS subject_id, id_index from grouper_members gm """ + " where subject_id in (" + GrouperClientUtils.appendQuestions(batchPennids.size()) + ")"; GcDbAccess gcDbAccess = new GcDbAccess().sql(sql).connectionName("awsProdReadonly"); for (String pennid : batchPennids) { gcDbAccess.addBindVar(pennid); loginIdToPennid.put(pennid, pennid); } List<Object[]> subjectIdIdIndexes = gcDbAccess.selectList(Object[].class); for (Object[] subjectIdIdIndex : subjectIdIdIndexes) { String subjectId = (String)subjectIdIdIndex[0]; Long idIndex = GrouperUtil.longValue(subjectIdIdIndex[1]); batchPennidsSet.remove(subjectId); loginIdToIdIndex.put(subjectId, idIndex); } for (String pennid : batchPennidsSet) { Subject subject = SubjectFinder.findByIdAndSource(pennid, "pennperson", false); if (subject == null) { if (subjectsPennIdNotFound < 10) { debugMap.put("subjectNotFound_" + subjectsPennIdNotFound, pennid); } subjectsPennIdNotFound++; continue; } Member member = MemberFinder.findBySubject(grouperSession, subject, true); if (OtherJobScript.retrieveFromThreadLocal() != null) { OtherJobScript.retrieveFromThreadLocal().getOtherJobInput().getHib3GrouperLoaderLog().addInsertCount(1); } loginIdToIdIndex.put(pennid, member.getIdIndex()); if (membersPennIdCreated < 10) { debugMap.put("memberCreated_" + membersPennIdCreated, pennid); } membersPennIdCreated++; } } debugMap.put("membersPennIdCreated", membersPennIdCreated); debugMap.put("subjectsPennIdNotFound", subjectsPennIdNotFound); // retrieve / create sps Map<String, Long> entityIdToIdIndex = new HashMap<String, Long>(); List<String> entityIdList = new ArrayList<String>(entityIds); numberOfBatches = GrouperUtil.batchNumberOfBatches(entityIdList.size(), batchSize, false); int entityIdsCreated = 0; Long maxEntityIdIndex = new GcDbAccess().sql("select max(id_index) from sso_prod_entity_id").select(long.class); if (maxEntityIdIndex == null) { maxEntityIdIndex = 0L; } else { maxEntityIdIndex++; } List<List<Object>> entityIdIdIndexToCreate = new ArrayList<>(); Map<String, String> entityIdToFrontDoorGroupName = new HashMap<>(); for (int i=0;i<numberOfBatches;i++) { List<String> batchEntityIds = GrouperUtil.batchList(entityIdList, batchSize, i); Set<String> batchEntityIdsSet = new HashSet<String>(batchEntityIds); String sql = "select spei.entity_id, spei.id_index, spefd.front_door_policy_group from sso_prod_entity_id spei " + " left join sso_prod_entity_front_door spefd on spei.entity_id = spefd.entity_id " + " where spei.entity_id in (" + GrouperClientUtils.appendQuestions(batchEntityIds.size()) + ")"; GcDbAccess gcDbAccess = new GcDbAccess().connectionName("awsProdReadonly").sql(sql); for (String sp : batchEntityIds) { gcDbAccess.addBindVar(sp); } List<Object[]> entityIdIdIndexGroupNames = gcDbAccess.selectList(Object[].class); for (Object[] entityIdIdIndexGroupName : entityIdIdIndexGroupNames) { String entityId = (String)entityIdIdIndexGroupName[0]; Long idIndex = GrouperUtil.longValue(entityIdIdIndexGroupName[1]); String frontDoorGroupName = (String)entityIdIdIndexGroupName[2]; batchEntityIdsSet.remove(entityId); entityIdToIdIndex.put(entityId, idIndex); if (!StringUtils.isBlank(frontDoorGroupName)) { entityIdToFrontDoorGroupName.put(entityId, frontDoorGroupName); } } for (String entityId : batchEntityIdsSet) { entityIdToIdIndex.put(entityId, maxEntityIdIndex); entityIdIdIndexToCreate.add(GrouperUtil.toListObject(entityId, maxEntityIdIndex)); if (OtherJobScript.retrieveFromThreadLocal() != null) { OtherJobScript.retrieveFromThreadLocal().getOtherJobInput().getHib3GrouperLoaderLog().addInsertCount(1); } if (entityIdsCreated < 10) { debugMap.put("entityIdCreated_" + entityIdsCreated, entityId); } entityIdsCreated++; maxEntityIdIndex++; } } new GcDbAccess().sql("insert into sso_prod_entity_id (entity_id, id_index) values (?, ?)").batchBindVars(entityIdIdIndexToCreate).executeBatchSql(); // insert data int logRecordsCreated = 0; int subjectsIdIndexNotFound = 0; Long maxLogRecordIdIndex = new GcDbAccess().sql("select max(id_index) from sso_prod_logs_person_sp").select(long.class); if (maxLogRecordIdIndex == null) { maxLogRecordIdIndex = 0L; } else { maxLogRecordIdIndex++; } Map<String, Set<Long>> entityIdHasFrontDoorGroupHasMemberIdIndexes = new HashMap(); for (String entityId : entityIdToFrontDoorGroupName.keySet()) { String frontDoorGroupName = entityIdToFrontDoorGroupName.get(entityId); Set<String> pennkeyOrPennids = entityIdToPennkeyOrPennid.get(entityId); List<Long> memberIdIndexes = new ArrayList<>(); for (String pennkeyOrPennid : pennkeyOrPennids) { Long memberIdIndex = loginIdToIdIndex.get(pennkeyOrPennid); if (memberIdIndex != null) { memberIdIndexes.add(memberIdIndex); } } Set<Long> memberIdsInGroup = memberIdIndexInGroup(frontDoorGroupName, memberIdIndexes); entityIdHasFrontDoorGroupHasMemberIdIndexes.put(entityId, memberIdsInGroup); } Set<Long> memberIdIndexes = new HashSet<>(loginIdToIdIndex.values()); Set<Long> twoStepMemberIdIndexes = memberIdIndexInGroup("penn:isc:ts:iam:weblogin:service:policy:idpCoarseGrained:enrolledInTwoStep", memberIdIndexes); Set<Long> workforceMemberIdIndexes = memberIdIndexInGroup("penn:isc:ts:iam:weblogin:service:policy:idpCoarseGrained:idpWorkforce", memberIdIndexes); Set<Long> memberMemberIdIndexes = memberIdIndexInGroup("penn:isc:ts:iam:weblogin:service:policy:idpCoarseGrained:member", memberIdIndexes); Set<Long> affiliateMemberIdIndexes = memberIdIndexInGroup("penn:isc:ts:iam:weblogin:service:policy:idpCoarseGrained:idpAffiliate", memberIdIndexes); Set<Long> recentAffiliateMemberIdIndexes = memberIdIndexInGroup("penn:isc:ts:iam:weblogin:service:policy:idpCoarseGrained:idpRecentAffiliate", memberIdIndexes); Set<Long> alumOrAffiliateMemberIdIndexes = memberIdIndexInGroup("penn:isc:ts:iam:weblogin:service:policy:idpCoarseGrained:idpAffiliateOrAlum", memberIdIndexes); Set<Long> uphsOnlyMemberIdIndexes = memberIdIndexInGroup("penn:community:uphsOnly", memberIdIndexes); Set<Long> alumOnlyMemberIdIndexes = memberIdIndexInGroup("penn:community:alumni:alumniOnly", memberIdIndexes); Set<Long> lockedOutMemberIdIndexes = memberIdIndexInGroup("penn:etc:deprovisioning:usersWhoHaveBeenDeprovisioned_employee", memberIdIndexes); Set<Long> uphsNotPennpayNotStudentMemberIdIndexes = memberIdIndexInGroup("penn:community:uphsNotPennpayNotStudent", memberIdIndexes); List<List<Object>> logRecordIdIndexUserIndexSpIndexTimestamp = new ArrayList<>(); for (Object[] timeUserSp : timeUserSps) { Timestamp timestamp = (Timestamp)timeUserSp[0]; String pennkey = (String)timeUserSp[1]; Long userIdIndex = loginIdToIdIndex.get(pennkey); String pennid = loginIdToPennid.get(pennkey); String entityId = (String)timeUserSp[2]; Long entityIdIdIndex = entityIdToIdIndex.get(entityId); if (userIdIndex == null) { if (subjectsIdIndexNotFound < 10) { debugMap.put("subjectsIdIndexNotFound_" + subjectsIdIndexNotFound, entityId); } subjectsIdIndexNotFound++; continue; } Integer inFrontDoor = null; String frontDoorGroupName = entityIdToFrontDoorGroupName.get(entityId); if (!StringUtils.isBlank(frontDoorGroupName)) { Set<Long> memberIdsInFrontDoorGroup = entityIdHasFrontDoorGroupHasMemberIdIndexes.get(entityId); inFrontDoor = memberIdsInFrontDoorGroup != null && memberIdsInFrontDoorGroup.contains(userIdIndex) ? 1 : 0; } Integer nonPersistent = null; if (!StringUtils.isBlank(pennid)) { nonPersistent = pennid.startsWith("9") ? 1 : 0; } logRecordIdIndexUserIndexSpIndexTimestamp.add(GrouperUtil.toListObject(maxLogRecordIdIndex, userIdIndex, entityIdIdIndex, timestamp, twoStepMemberIdIndexes.contains(userIdIndex) ? 1 : 0, workforceMemberIdIndexes.contains(userIdIndex) ? 1 : 0, memberMemberIdIndexes.contains(userIdIndex) ? 1 : 0, affiliateMemberIdIndexes.contains(userIdIndex) ? 1 : 0, recentAffiliateMemberIdIndexes.contains(userIdIndex) ? 1 : 0, alumOrAffiliateMemberIdIndexes.contains(userIdIndex) ? 1 : 0, uphsOnlyMemberIdIndexes.contains(userIdIndex) ? 1 : 0, alumOnlyMemberIdIndexes.contains(userIdIndex) ? 1 : 0, inFrontDoor, lockedOutMemberIdIndexes.contains(userIdIndex) ? 1 : 0, nonPersistent, uphsNotPennpayNotStudentMemberIdIndexes.contains(userIdIndex) ? 1 : 0)); if (OtherJobScript.retrieveFromThreadLocal() != null) { OtherJobScript.retrieveFromThreadLocal().getOtherJobInput().getHib3GrouperLoaderLog().addInsertCount(1); } if (logRecordsCreated < 10) { debugMap.put("logRecordsCreated_" + logRecordsCreated, timestamp.toString() + ", " + pennkey + ", " + entityId); } logRecordsCreated++; maxLogRecordIdIndex++; } new GcDbAccess().sql("insert into sso_prod_logs_person_sp (id_index, user_member_id_index, sp_entity_id_index, login_timestamp, two_step_enrolled, workforce, member, " + " affiliate, recent_affiliate, alum_or_affiliate, uphs_only, alum_only, in_front_door, locked_out, " + "non_persistent, uphs_not_pennpay_not_student) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"). batchBindVars(logRecordIdIndexUserIndexSpIndexTimestamp).executeBatchSql(); debugMap.put("subjectsIdIndexNotFound", subjectsIdIndexNotFound); debugMap.put("logRecordsCreated", logRecordsCreated); if (OtherJobScript.retrieveFromThreadLocal() != null) { OtherJobScript.retrieveFromThreadLocal().getOtherJobInput().getHib3GrouperLoaderLog().appendJobMessage(GrouperUtil.mapToString(debugMap)); } else { System.exit(0); } // } //}
Managers and owners in Grouper for each service provider
Manage front door with GSH template
Config
grouperGshTemplate.ssoCoarseGrainedAuthzConfig.defaultRunButtonFolderUuidOrName = penn\u003Aisc\u003Ats\u003Aiam\u003Aweblogin\u003Aservice\u003Atemplates\u003AidpRegistrationProd grouperGshTemplate.ssoCoarseGrainedAuthzConfig.displayErrorOutput = true grouperGshTemplate.ssoCoarseGrainedAuthzConfig.folderShowOnDescendants = certainFolders grouperGshTemplate.ssoCoarseGrainedAuthzConfig.folderShowType = certainFolders grouperGshTemplate.ssoCoarseGrainedAuthzConfig.folderUuidToShow = penn\u003Aisc\u003Ats\u003Aiam\u003Aweblogin\u003Aservice\u003Atemplates\u003AidpRegistrationProd grouperGshTemplate.ssoCoarseGrainedAuthzConfig.groupUuidCanRun = penn\u003Aisc\u003Ats\u003Aiam\u003Aweblogin\u003Aservice\u003Asecurity\u003AcanRunIdpTemplate grouperGshTemplate.ssoCoarseGrainedAuthzConfig.gshTemplate = // grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.0.description = What do you want to do with front door config? add, edit, delete, enable, disable grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.0.dropdownCsvValue = add, edit, delete, enable, disable grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.0.formElementType = dropdown grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.0.index = 10 grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.0.label = Action grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.0.name = gsh_input_action grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.0.required = true grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.1.description = Entity ID of the service provider grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.1.dropdownValueFormat = dynamicFromTemplate grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.1.formElementType = dropdown grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.1.index = 20 grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.1.label = Entity ID grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.1.name = gsh_input_entityId grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.1.required = true grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.1.showEl = \u0024{gsh_input_action == 'add' || gsh_input_action == 'edit' || gsh_input_action == 'delete'} grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.10.defaultValue = generic grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.10.description = Generic is the built-in error page. Customized is the generic page but with customized text. Other URL will redirect to another URL for the error page. The default value is 'generic'. grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.10.dropdownCsvValue = generic, customized, other_url grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.10.formElementType = dropdown grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.10.index = 120 grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.10.label = Error page type grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.10.name = gsh_input_errorPageType grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.10.showEl = \u0024{ (gsh_input_action == 'add' || gsh_input_action == 'edit') && !org.apache.commons.lang3.StringUtils.isBlank(gsh_input_entityId ) } grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.11.description = URL to redirect to for an error for this app grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.11.index = 130 grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.11.label = Error page URL grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.11.maxLength = 2000 grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.11.name = gsh_input_errorPageUrl grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.11.showEl = \u0024{ (gsh_input_action == 'add' || gsh_input_action == 'edit') && !org.apache.commons.lang3.StringUtils.isBlank(gsh_input_entityId ) } grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.11.validationType = none grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.12.description = Enter the HTML to be added to the error page grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.12.formElementType = textarea grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.12.index = 140 grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.12.label = Error page text HTML grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.12.maxLength = 4000 grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.12.name = gsh_input_errorPageText grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.12.showEl = \u0024{ (gsh_input_action == 'add' || gsh_input_action == 'edit') && !org.apache.commons.lang3.StringUtils.isBlank(gsh_input_entityId ) } grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.12.validationType = none grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.13.description = Enter the ID path of the group which is the policy group for this service provider. This is separate from the front door policy grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.13.index = 80 grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.13.label = Policy group name grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.13.maxLength = 1000 grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.13.name = gsh_input_policyGroupName grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.13.showEl = \u0024{ (gsh_input_action == 'add' || gsh_input_action == 'edit') && !org.apache.commons.lang3.StringUtils.isBlank(gsh_input_entityId ) } grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.13.validationType = none grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.2.description = Write a short but descriptive name for this service provider. If this is an application for a certain team or organization, include that. If there are multiple environments (e.g. dev / test / prod). For example\u003A ISC Jira prod. grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.2.index = 30 grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.2.label = App name grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.2.maxLength = 100 grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.2.name = gsh_input_name grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.2.required = true grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.2.showEl = \u0024{ (gsh_input_action == 'add' || gsh_input_action == 'edit') && !org.apache.commons.lang3.StringUtils.isBlank(gsh_input_entityId ) } grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.2.validationType = none grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.3.description = Describe the application so that it can be easily searched for or differentiated from other service providers. grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.3.formElementType = textarea grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.3.index = 40 grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.3.label = Description grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.3.maxLength = 2000 grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.3.name = gsh_input_description grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.3.required = true grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.3.showEl = \u0024{ (gsh_input_action == 'add' || gsh_input_action == 'edit') && !org.apache.commons.lang3.StringUtils.isBlank(gsh_input_entityId ) } grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.3.trimWhitespace = true grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.3.validationType = none grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.4.description = Admins can manage the settings of this service provider. Input a comma separated list of pennkeys, pennids, or penngroup ID paths who admin this service provider. grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.4.index = 50 grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.4.label = Admins grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.4.maxLength = 2000 grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.4.name = gsh_input_adminGroup grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.4.showEl = \u0024{ gsh_input_action == 'add' && !org.apache.commons.lang3.StringUtils.isBlank(gsh_input_action ) && !org.apache.commons.lang3.StringUtils.isBlank(gsh_input_entityId ) } grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.4.validationType = none grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.5.description = Owners can manage the settings of this service provider and can manage the list of managers and owners. Input a comma separated list of pennkeys, pennids, or penngroup ID paths who own this service provider. grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.5.index = 60 grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.5.label = Owners grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.5.maxLength = 2000 grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.5.name = gsh_input_ownerGroup grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.5.showEl = \u0024{ gsh_input_action == 'add' && !org.apache.commons.lang3.StringUtils.isBlank(gsh_input_action ) && !org.apache.commons.lang3.StringUtils.isBlank(gsh_input_entityId ) } grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.5.validationType = none grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.6.description = Select the coarse grained policy group that users must be in to access the application. See the PennGroups wiki for information. grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.6.dropdownCsvValue = workforceInTwoStep, workforce, memberInTwoStep, member, affiliateInTwoStep, affiliate, affiliateOrAlumInTwoStep, affiliateOrAlum, inTwoStep, recentAffiliate, recentAffiliateInTwoStep, none grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.6.dropdownValueFormat = csv grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.6.formElementType = dropdown grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.6.index = 70 grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.6.label = Front door reference group grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.6.name = gsh_input_frontDoorPolicy grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.6.showEl = \u0024{ (gsh_input_action == 'add' || gsh_input_action == 'edit') && !org.apache.commons.lang3.StringUtils.isBlank(gsh_input_entityId ) } grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.7.description = Enter a URL of this application that can be used to test or tell users to log in. If there is no one URL, then provide a jump page, service page, or one of the URLs. grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.7.index = 90 grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.7.label = URL of this application grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.7.maxLength = 2000 grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.7.name = gsh_input_url grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.7.required = true grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.7.showEl = \u0024{ (gsh_input_action == 'add' || gsh_input_action == 'edit') && !org.apache.commons.lang3.StringUtils.isBlank(gsh_input_entityId ) } grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.7.validationType = none grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.8.description = Provide instructions for logging in to the application especially if it is not obvious. grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.8.formElementType = textarea grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.8.index = 100 grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.8.label = URL instructions grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.8.maxLength = 2000 grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.8.name = gsh_input_urlInstructions grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.8.required = true grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.8.showEl = \u0024{ (gsh_input_action == 'add' || gsh_input_action == 'edit') && !org.apache.commons.lang3.StringUtils.isBlank(gsh_input_entityId ) } grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.8.validationType = none grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.9.defaultValue = false grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.9.description = If the front door group(s) (usually the reference group, but could be policy group) requires Two-step and the error page can help users then set this to true. This does not require Two-step and only affects the error page. grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.9.index = 110 grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.9.label = Policy requires Two-step grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.9.name = gsh_input_requiresTwostep grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.9.showEl = \u0024{ (gsh_input_action == 'add' || gsh_input_action == 'edit') && !org.apache.commons.lang3.StringUtils.isBlank(gsh_input_entityId ) } grouperGshTemplate.ssoCoarseGrainedAuthzConfig.input.9.type = boolean grouperGshTemplate.ssoCoarseGrainedAuthzConfig.moreActionsLabel = WebLogin front door authorization config grouperGshTemplate.ssoCoarseGrainedAuthzConfig.numberOfInputs = 14 grouperGshTemplate.ssoCoarseGrainedAuthzConfig.runAsType = GrouperSystem grouperGshTemplate.ssoCoarseGrainedAuthzConfig.runButtonGroupOrFolder = folder grouperGshTemplate.ssoCoarseGrainedAuthzConfig.securityRunType = specifiedGroup grouperGshTemplate.ssoCoarseGrainedAuthzConfig.showInMoreActions = true grouperGshTemplate.ssoCoarseGrainedAuthzConfig.showOnFolders = true grouperGshTemplate.ssoCoarseGrainedAuthzConfig.templateDescription = Configure a Service Provider's settings for front door authorization grouperGshTemplate.ssoCoarseGrainedAuthzConfig.templateName = WebLogin front door authorization config grouperGshTemplate.ssoCoarseGrainedAuthzConfig.templateType = gsh grouperGshTemplate.ssoCoarseGrainedAuthzConfig.templateVersion = V2
Source
import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.HexFormat; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.lang3.StringUtils; import edu.internet2.middleware.grouper.Group; import edu.internet2.middleware.grouper.GroupFinder; import edu.internet2.middleware.grouper.GroupSave; import edu.internet2.middleware.grouper.GrouperSession; import edu.internet2.middleware.grouper.SubjectFinder; import edu.internet2.middleware.grouper.app.gsh.template.GshTemplateConfig; import edu.internet2.middleware.grouper.app.gsh.template.GshTemplateDecorateForUiInput; import edu.internet2.middleware.grouper.app.gsh.template.GshTemplateInputConfigAndValue; import edu.internet2.middleware.grouper.app.gsh.template.GshTemplateOutput; import edu.internet2.middleware.grouper.app.gsh.template.GshTemplateRuntime; import edu.internet2.middleware.grouper.app.gsh.template.GshTemplateV2; import edu.internet2.middleware.grouper.app.gsh.template.GshTemplateV2input; import edu.internet2.middleware.grouper.app.gsh.template.GshTemplateV2output; import edu.internet2.middleware.grouper.exception.GrouperSessionException; import edu.internet2.middleware.grouper.ldap.LdapAttribute; import edu.internet2.middleware.grouper.ldap.LdapEntry; import edu.internet2.middleware.grouper.ldap.LdapModificationItem; import edu.internet2.middleware.grouper.ldap.LdapModificationType; import edu.internet2.middleware.grouper.ldap.LdapSessionUtils; import edu.internet2.middleware.grouper.misc.GrouperSessionHandler; import edu.internet2.middleware.grouper.privs.AccessPrivilege; import edu.internet2.middleware.grouper.util.GrouperUtil; import edu.internet2.middleware.grouperClient.collections.MultiKey; import edu.internet2.middleware.grouperClient.jdbc.GcDbAccess; import edu.internet2.middleware.subject.Subject; public class Test76ssoCoarseGrainedConfig extends GshTemplateV2 { @Override public void decorateTemplateForUiDisplay( GshTemplateDecorateForUiInput gshTemplateDecorateForUiInput) { String stemName = gshTemplateDecorateForUiInput.getOwnerStemName(); boolean prod = StringUtils.equals(stemName, "penn:isc:ts:iam:weblogin:service:templates:idpRegistrationProd"); if (!stemName.equals("penn:isc:ts:iam:weblogin:service:templates:idpRegistrationStage") && !stemName.equals("penn:isc:ts:iam:weblogin:service:templates:idpRegistrationProd")) { throw new RuntimeException("Invalid owner folder, should start with: 'penn:isc:ts:iam:weblogin:service:templates:' and be prod or stage"); } String adminGroupName = "penn:isc:ts:iam:weblogin:service:policy:idpFrontDoorStaging:security:idpFrontDoorStagingUpdaters"; // ssoFrontDoor_shibdev2_access_admins String managerFolderPrefix = "penn:isc:ts:iam:weblogin:service:policy:idpFrontDoorStaging:service:policy:managers:"; String tableName = "sso_stage_entity_front_door"; if (prod) { tableName = "sso_prod_entity_front_door"; adminGroupName = "penn:isc:ts:iam:weblogin:service:policy:idpFrontDoorProd:security:idpFrontDoorProdUpdaters"; managerFolderPrefix = "penn:isc:ts:iam:weblogin:service:policy:idpFrontDoorProd:service:policy:managers:"; } Group adminGroup = GroupFinder.findByName(adminGroupName, true); boolean isAdmin = adminGroup.hasMember(gshTemplateDecorateForUiInput.getCurrentSubject()); Map<String, GshTemplateInputConfigAndValue> gshTemplateInputConfigAndValues = gshTemplateDecorateForUiInput.getGshTemplateInputConfigAndValues(); GshTemplateInputConfigAndValue action = gshTemplateInputConfigAndValues.get("gsh_input_action"); GshTemplateInputConfigAndValue entityIdInput = gshTemplateInputConfigAndValues.get("gsh_input_entityId"); GshTemplateInputConfigAndValue nameInput = gshTemplateInputConfigAndValues.get("gsh_input_name"); GshTemplateInputConfigAndValue descriptionInput = gshTemplateInputConfigAndValues.get("gsh_input_description"); GshTemplateInputConfigAndValue adminsInput = gshTemplateInputConfigAndValues.get("gsh_input_admins"); GshTemplateInputConfigAndValue ownersInput = gshTemplateInputConfigAndValues.get("gsh_input_owners"); GshTemplateInputConfigAndValue frontDoorPolicyInput = gshTemplateInputConfigAndValues.get("gsh_input_frontDoorPolicy"); GshTemplateInputConfigAndValue urlInput = gshTemplateInputConfigAndValues.get("gsh_input_url"); GshTemplateInputConfigAndValue urlInstructionsInput = gshTemplateInputConfigAndValues.get("gsh_input_urlInstructions"); GshTemplateInputConfigAndValue requiresTwoStepInput = gshTemplateInputConfigAndValues.get("gsh_input_requiresTwostep"); GshTemplateInputConfigAndValue errorPageTypeInput = gshTemplateInputConfigAndValues.get("gsh_input_errorPageType"); GshTemplateInputConfigAndValue errorPageUrlInput = gshTemplateInputConfigAndValues.get("gsh_input_errorPageUrl"); GshTemplateInputConfigAndValue errorPageTextInput = gshTemplateInputConfigAndValues.get("gsh_input_errorPageText"); GshTemplateInputConfigAndValue policyGroupNameInput = gshTemplateInputConfigAndValues.get("gsh_input_policyGroupName"); if (StringUtils.equals(action.getValue(), "add")) { List<String> entityIds = new GcDbAccess().sql("select entity_id from sso_prod_entity_id spei where not exists (select 1 from " + tableName + " sefd where sefd.entity_id = spei.entity_id) order by 1").selectList(String.class); List<MultiKey> keysAndValues = new ArrayList<MultiKey>(); keysAndValues.add(new MultiKey("", "")); for (String entityId : entityIds) { keysAndValues.add(new MultiKey(entityId, entityId)); } entityIdInput.getGshTemplateInputConfig().setDropdownKeysAndLabels(keysAndValues); } else if (StringUtils.equals(action.getValue(), "delete") || StringUtils.equals(action.getValue(), "edit")) { List<String> entityIds = null; if (isAdmin) { entityIds = new GcDbAccess().sql("select entity_id from " + tableName + " order by 1").selectList(String.class); } else { entityIds = new GcDbAccess().sql(String.format(""" select entity_id from %s stefd WHERE EXISTS (SELECT 1 FROM GROUPER_MEMBERSHIPS_LW_V gmlv WHERE gmlv.SUBJECT_ID = ? AND gmlv.SUBJECT_SOURCE = 'pennperson' AND gmlv.LIST_NAME = 'members' AND gmlv.GROUP_NAME = '%sssoFrontDoor_' || stefd.name_without_special_characters || '_admins') order by 1 """, tableName, managerFolderPrefix)).addBindVar(gshTemplateDecorateForUiInput.getCurrentSubject().getId()).selectList(String.class); } List<MultiKey> keysAndValues = new ArrayList<MultiKey>(); keysAndValues.add(new MultiKey("", "")); for (String entityId : entityIds) { keysAndValues.add(new MultiKey(entityId, entityId)); } entityIdInput.getGshTemplateInputConfig().setDropdownKeysAndLabels(keysAndValues); } // gsh_input_action // gsh_input_entityId // gsh_input_name // gsh_input_description // gsh_input_admins // gsh_input_owners // gsh_input_frontDoorPolicy // gsh_input_url // gsh_input_urlInstructions // gsh_input_requiresTwostep if (StringUtils.equals(gshTemplateDecorateForUiInput.getEventConfigId(), "gsh_input_action")) { if (entityIdInput != null) { entityIdInput.setValue(null); } } if (StringUtils.equals(gshTemplateDecorateForUiInput.getEventConfigId(), "gsh_input_action") || (entityIdInput != null && StringUtils.isBlank(entityIdInput.getValue())) || (StringUtils.equals(gshTemplateDecorateForUiInput.getEventConfigId(), "gsh_input_entityId") && StringUtils.equals(action.getValue(), "add"))) { if (nameInput != null) { nameInput.setValue(null); } if (descriptionInput != null) { descriptionInput.setValue(null); } if (adminsInput != null) { adminsInput.setValue(null); } if (ownersInput != null) { ownersInput.setValue(null); } if (frontDoorPolicyInput != null) { frontDoorPolicyInput.setValue(null); } if (urlInput != null) { urlInput.setValue(null); } if (urlInstructionsInput != null) { urlInstructionsInput.setValue(null); } if (requiresTwoStepInput != null) { requiresTwoStepInput.setValue(null); } if (errorPageTypeInput != null) { errorPageTypeInput.setValue(null); } if (errorPageUrlInput != null) { errorPageUrlInput.setValue(null); } if (errorPageTextInput != null) { errorPageTextInput.setValue(null); } if (policyGroupNameInput != null) { policyGroupNameInput.setValue(null); } } if (StringUtils.equals(gshTemplateDecorateForUiInput.getEventConfigId(), "gsh_input_entityId") && StringUtils.equals(action.getValue(), "edit") && entityIdInput != null && !StringUtils.isBlank(entityIdInput.getValue())) { String entityId = entityIdInput.getValue(); Object[] dataRow = new GcDbAccess().sql("select name_without_special_characters, name, description, url, url_instructions, " + "coarse_grained_policy, requires_twostep, error_page_type, error_page_url, error_page_text, front_door_policy_group from " + tableName + " where entity_id = ?").addBindVar(entityId). select(Object[].class); String nameWithoutSpecialCharacters = (String)dataRow[0]; String name = (String)dataRow[1]; String description = (String)dataRow[2]; String url = (String)dataRow[3]; String urlInstructions = (String)dataRow[4]; String coarseGrainedPolicy = (String)dataRow[5]; String requiresTwostep = (String)dataRow[6]; String errorPageType = (String)dataRow[7]; String errorPageUrl = (String)dataRow[8]; String errorPageText = (String)dataRow[9]; String policyFrontDoorGroup = (String)dataRow[10]; nameInput.setValue(name); descriptionInput.setValue(description); urlInput.setValue(url); urlInstructionsInput.setValue(urlInstructions); frontDoorPolicyInput.setValue(coarseGrainedPolicy); requiresTwoStepInput.setValue(GrouperUtil.booleanValue(requiresTwostep, false) ? "true" : "false"); errorPageTypeInput.setValue(errorPageType); errorPageUrlInput.setValue(errorPageUrl); errorPageTextInput.setValue(errorPageText); policyGroupNameInput.setValue(policyFrontDoorGroup); } } Map<String, String> bucketLabelToGroupName = GrouperUtil.toMap( "workforceInTwoStep", "penn:isc:ts:iam:weblogin:service:policy:idpCoarseGrained:employeesInTwoStep", "workforce", "penn:isc:ts:iam:weblogin:service:policy:idpCoarseGrained:idpWorkforce", "memberInTwoStep", "penn:isc:ts:iam:weblogin:service:policy:idpCoarseGrained:memberInTwoStep", "member", "penn:isc:ts:iam:weblogin:service:policy:idpCoarseGrained:member", "affiliateInTwoStep", "penn:isc:ts:iam:weblogin:service:policy:idpCoarseGrained:idpAffiliateInTwoStep", "affiliate", "penn:isc:ts:iam:weblogin:service:policy:idpCoarseGrained:idpAffiliate", "affiliateOrAlumInTwoStep", "penn:isc:ts:iam:weblogin:service:policy:idpCoarseGrained:idpAffiliateOrAlumInTwoStep", "affiliateOrAlum", "penn:isc:ts:iam:weblogin:service:policy:idpCoarseGrained:idpAffiliateOrAlum", "inTwoStep", "penn:isc:ts:iam:weblogin:service:policy:idpCoarseGrained:enrolledInTwoStep", "recentAffiliateInTwoStep", "penn:isc:ts:iam:weblogin:service:policy:idpCoarseGrained:idpRecentAffiliateInTwoStep", "recentAffiliate", "penn:isc:ts:iam:weblogin:service:policy:idpCoarseGrained:idpRecentAffiliate", "none", "none"); public void convertListOfSubjectStringsToSubjects(String inputName, String subjectsString, Set<Subject> subjects, GshTemplateOutput gsh_builtin_gshTemplateOutput) { Set<String> subjectStringSet = GrouperUtil.splitTrimToSet(subjectsString, ","); for (String subjectString : subjectStringSet) { if (subjectString.contains(":")) { Group group = GroupFinder.findByName(subjectString, false); if (group == null) { gsh_builtin_gshTemplateOutput.addValidationLine(inputName, "Cannot find group: '" + subjectString + "'"); } else { subjects.add(group.toSubject()); } } else { Subject subject = SubjectFinder.findByIdOrIdentifierAndSource(subjectString, "pennperson", false); if (subject == null) { gsh_builtin_gshTemplateOutput.addValidationLine(inputName, "Cannot find person: '" + subjectString + "'"); } else { subjects.add(subject); } } } } /** * TODO remove after upgrade * encrypt a message to SHA * @param plaintext * @return the hash */ public synchronized String encryptShaHex(String plaintext) { MessageDigest md = null; try { md = MessageDigest.getInstance("SHA"); //step 2 } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } try { md.update(plaintext.getBytes("UTF-8")); //step 3 } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } byte[] raw = md.digest(); //step 4 String hex = HexFormat.of().formatHex(raw); return hex; //step 6 } public void createLdapModificationItem(List<LdapModificationItem> ldapModificationItems, String attributeName, String oldValue, String newValue) { if (StringUtils.isBlank(oldValue)) { ldapModificationItems.add(new LdapModificationItem(LdapModificationType.ADD_ATTRIBUTE, new LdapAttribute(attributeName, newValue))); } else if (StringUtils.isBlank(newValue)) { ldapModificationItems.add(new LdapModificationItem(LdapModificationType.REMOVE_ATTRIBUTE, new LdapAttribute(attributeName))); } else { ldapModificationItems.add(new LdapModificationItem(LdapModificationType.REPLACE_ATTRIBUTE, new LdapAttribute(attributeName, newValue))); } } @Override public void gshRunLogic(GshTemplateV2input gshTemplateV2input, GshTemplateV2output gshTemplateV2output) { Subject subjectLoggedIn = gshTemplateV2input.getGsh_builtin_gshTemplateRuntime().getCurrentSubject(); // Analyze user access, Analyze user history, Analyze application String gsh_input_action = gshTemplateV2input.getGsh_builtin_inputString("gsh_input_action"); String gsh_input_entityId = gshTemplateV2input.getGsh_builtin_inputString("gsh_input_entityId"); String gsh_input_name = gshTemplateV2input.getGsh_builtin_inputString("gsh_input_name"); String gsh_input_description = gshTemplateV2input.getGsh_builtin_inputString("gsh_input_description"); String gsh_input_admins = gshTemplateV2input.getGsh_builtin_inputString("gsh_input_admins"); String gsh_input_owners = gshTemplateV2input.getGsh_builtin_inputString("gsh_input_owners"); String gsh_input_frontDoorPolicy = gshTemplateV2input.getGsh_builtin_inputString("gsh_input_frontDoorPolicy"); String gsh_input_url = gshTemplateV2input.getGsh_builtin_inputString("gsh_input_url"); String gsh_input_urlInstructions = gshTemplateV2input.getGsh_builtin_inputString("gsh_input_urlInstructions"); boolean gsh_input_requiresTwostep = gshTemplateV2input.getGsh_builtin_inputBoolean("gsh_input_requiresTwostep"); String gsh_input_errorPageType = gshTemplateV2input.getGsh_builtin_inputString("gsh_input_errorPageType"); String gsh_input_errorPageText = gshTemplateV2input.getGsh_builtin_inputString("gsh_input_errorPageText"); String gsh_input_errorPageUrl = gshTemplateV2input.getGsh_builtin_inputString("gsh_input_errorPageUrl"); String gsh_input_policyGroupName = gshTemplateV2input.getGsh_builtin_inputString("gsh_input_policyGroupName"); String stemName = gshTemplateV2input.getGsh_builtin_ownerStemName(); boolean prod = StringUtils.equals(stemName, "penn:isc:ts:iam:weblogin:service:templates:idpRegistrationProd"); if (!stemName.startsWith("penn:isc:ts:iam:weblogin:service:templates:")) { throw new RuntimeException("Invalid owner folder, should start with: 'penn:isc:ts:iam:weblogin:service:templates:'"); } String adminGroupName = "penn:isc:ts:iam:weblogin:service:policy:idpFrontDoorStaging:security:idpFrontDoorStagingUpdaters"; String tableName = "sso_stage_entity_front_door"; String ldapConnection = "iamLdapStagingApplications"; String pennGroupsFolderExtension = "idpFrontDoorStaging"; String canRunTemplateGroupName = "penn:isc:ts:iam:weblogin:service:security:canRunIdpTemplateStage"; if (prod) { tableName = "sso_prod_entity_front_door"; ldapConnection = "iamLdapProdApplications"; pennGroupsFolderExtension = "idpFrontDoorProd"; canRunTemplateGroupName = "penn:isc:ts:iam:weblogin:service:security:canRunIdpTemplate"; adminGroupName = "penn:isc:ts:iam:weblogin:service:policy:idpFrontDoorProd:security:idpFrontDoorProdUpdaters"; } GshTemplateOutput gsh_builtin_gshTemplateOutput = gshTemplateV2output.getGsh_builtin_gshTemplateOutput(); gsh_builtin_gshTemplateOutput.assignRedirectToGrouperOperation("NONE"); Group adminGroup = GroupFinder.findByName(adminGroupName, true); boolean isAdmin = adminGroup.hasMember(subjectLoggedIn); String inputPolicyGroupEntitlement = null; if (!StringUtils.isBlank(gsh_input_policyGroupName)) { Group policyGroup = GroupFinder.findByName(gsh_input_policyGroupName, false); if (policyGroup == null) { gsh_builtin_gshTemplateOutput.addValidationLine("gsh_input_policyGroupName", "Policy group '" + gsh_input_policyGroupName + "' not found, make sure to copy/paste the ID path"); return; } inputPolicyGroupEntitlement = "urn:mace:upenn.edu:" + gsh_input_policyGroupName; } boolean actionAdd = StringUtils.equals("add", gsh_input_action); if (actionAdd && !isAdmin) { gsh_builtin_gshTemplateOutput.addValidationLine("gsh_input_action", "You are not allowed to add front door configurations, please use the remedy tile to request a configuration"); return; } boolean actionEdit = StringUtils.equals("edit", gsh_input_action); boolean actionDelete = StringUtils.equals("delete", gsh_input_action); if (!actionAdd && !actionDelete && !actionEdit) { gsh_builtin_gshTemplateOutput.addValidationLine("gsh_input_action", "Action not implemented yet, just add for now"); return; } if (StringUtils.equals(gsh_input_errorPageType, "customized") && StringUtils.isBlank(gsh_input_errorPageText)) { gsh_builtin_gshTemplateOutput.addValidationLine("gsh_input_errorPageText", "Error page text is required"); return; } if (StringUtils.equals(gsh_input_errorPageType, "other_url") && StringUtils.isBlank(gsh_input_errorPageUrl)) { gsh_builtin_gshTemplateOutput.addValidationLine("gsh_input_errorPageUrl", "Error page URL is required"); return; } if (!StringUtils.equals(gsh_input_errorPageType, "other_url") && !StringUtils.isBlank(gsh_input_errorPageUrl)) { gsh_builtin_gshTemplateOutput.addValidationLine("gsh_input_errorPageUrl", "Error page URL must be blank if the error page type is not 'other_url'"); return; } if (!StringUtils.equals(gsh_input_errorPageType, "customized") && !StringUtils.isBlank(gsh_input_errorPageText)) { gsh_builtin_gshTemplateOutput.addValidationLine("gsh_input_errorPageText", "Error page text must be blank if the error page type is not 'custommized'"); return; } String entityIdShaHex = encryptShaHex(gsh_input_entityId); String nameWithoutSpecialCharacters = gsh_input_name == null ? null : gsh_input_name.replaceAll("[^A-Za-z0-9_-]", "_"); if (actionEdit || actionDelete) { nameWithoutSpecialCharacters = new GcDbAccess().sql("select name_without_special_characters from " + tableName + " where entity_id = ?"). addBindVar(gsh_input_entityId).select(String.class); } // entity_id // entity_id_sha_hex // name_without_special_characters // name // description // url // url_instructions int rowsForNameWithoutSpecialChars = new GcDbAccess().sql("select count(1) from " + tableName + " where name_without_special_characters = ?"). addBindVar(nameWithoutSpecialCharacters).select(int.class); if (actionAdd && rowsForNameWithoutSpecialChars > 0) { gsh_builtin_gshTemplateOutput.addValidationLine("gsh_input_name", "Name conflicts with existing SP registration! '" + gsh_input_name + "'"); } if ((actionDelete || actionEdit) && rowsForNameWithoutSpecialChars != 1) { gsh_builtin_gshTemplateOutput.addValidationLine("gsh_input_name", "Name not found with existing SP registration! '" + gsh_input_name + "'"); } int rowsForEntityId = new GcDbAccess().sql("select count(1) from " + tableName + " where entity_id = ?"). addBindVar(gsh_input_entityId).select(int.class); if (actionAdd && rowsForEntityId > 0) { gsh_builtin_gshTemplateOutput.addValidationLine("gsh_input_entityId", "Entity ID conflicts with existing SP registration! '" + gsh_input_entityId + "'"); } if (actionEdit && rowsForEntityId != 1) { gsh_builtin_gshTemplateOutput.addValidationLine("gsh_input_entityId", "Cannot find entity ID! '" + gsh_input_entityId + "'"); } String groupExtensionAdmins = "ssoFrontDoor_" + nameWithoutSpecialCharacters + "_admins"; String groupExtensionOwners = "ssoFrontDoor_" + nameWithoutSpecialCharacters + "_owners"; String adminsGroupName = "penn:isc:ts:iam:weblogin:service:policy:" + pennGroupsFolderExtension + ":service:policy:managers:" + groupExtensionAdmins; Group adminsGroup = GroupFinder.findByName(adminsGroupName, false); if (!isAdmin) { if (adminsGroup == null) { gsh_builtin_gshTemplateOutput.addValidationLine("gsh_input_entityId", "Cannot find admins group! '" + groupExtensionAdmins + "'"); } else { if (!adminsGroup.hasMember(subjectLoggedIn)) { gsh_builtin_gshTemplateOutput.addValidationLine("gsh_input_entityId", "You are not allowed to make changes to this entity! '" + gsh_input_entityId + "'"); } } } Set<Subject> admins = new HashSet<>(); if (!StringUtils.isBlank(gsh_input_admins) && actionAdd) { convertListOfSubjectStringsToSubjects("gsh_input_admins", gsh_input_admins, admins, gsh_builtin_gshTemplateOutput); } Set<Subject> owners = new HashSet<>(); if (!StringUtils.isBlank(gsh_input_owners) && actionAdd) { convertListOfSubjectStringsToSubjects("gsh_input_owners", gsh_input_owners, owners, gsh_builtin_gshTemplateOutput); } if (StringUtils.isBlank(gsh_input_frontDoorPolicy)) { gsh_input_frontDoorPolicy = "none"; } if (GrouperUtil.length(gsh_builtin_gshTemplateOutput.getValidationLines()) > 0) { gsh_builtin_gshTemplateOutput.assignIsError(true); return; } if (actionAdd) { new GcDbAccess().sql("insert into " + tableName + " (entity_id, entity_id_sha_hex, " + "name_without_special_characters, name, description, url, url_instructions, coarse_grained_policy, front_door_policy_group, " + "requires_twostep, error_page_type, error_page_url, error_page_text) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) "). addBindVar(gsh_input_entityId).addBindVar(entityIdShaHex).addBindVar(nameWithoutSpecialCharacters). addBindVar(gsh_input_name).addBindVar(gsh_input_description).addBindVar(gsh_input_url). addBindVar(gsh_input_urlInstructions).addBindVar(gsh_input_frontDoorPolicy).addBindVar(gsh_input_policyGroupName). addBindVar(gsh_input_requiresTwostep ? "T" : "F").addBindVar(gsh_input_errorPageType). addBindVar(gsh_input_errorPageUrl).addBindVar(gsh_input_errorPageText).executeSql(); if (adminsGroup == null) { adminsGroup = new GroupSave().assignName(adminsGroupName).assignDescription("Admins for " + gsh_input_name + ". " + gsh_input_description).save(); } for (Subject subject : admins) { adminsGroup.addMember(subject, false); } String ownersGroupName = "penn:isc:ts:iam:weblogin:service:policy:" + pennGroupsFolderExtension + ":service:policy:managers:" + groupExtensionOwners; Group ownersGroup = new GroupSave().assignName(ownersGroupName).assignDescription("Owners for " + gsh_input_name + ". " + gsh_input_description).save(); for (Subject subject : owners) { ownersGroup.addMember(subject, false); } adminsGroup.addMember(ownersGroup.toSubject()); adminsGroup.grantPriv(ownersGroup.toSubject(), AccessPrivilege.UPDATE, false); adminsGroup.grantPriv(ownersGroup.toSubject(), AccessPrivilege.READ, false); ownersGroup.grantPriv(ownersGroup.toSubject(), AccessPrivilege.UPDATE, false); ownersGroup.grantPriv(ownersGroup.toSubject(), AccessPrivilege.READ, false); Group canRunTemplateGroup = GroupFinder.findByName(canRunTemplateGroupName, true); canRunTemplateGroup.addMember(adminsGroup.toSubject(), false); // cn=c77a2c1fd25902a3e09e313af5cd4d0da29b7405,ou=applications,dc=penncommunity,dc=upenn,dc=edu String dn = "cn=" + entityIdShaHex + ",ou=applications,dc=authz,dc=upenn,dc=edu"; LdapEntry ldapEntry = new LdapEntry(dn); ldapEntry.addAttribute(new LdapAttribute("cn", entityIdShaHex)); ldapEntry.addAttribute(new LdapAttribute("objectClass", "sAMLApp")); ldapEntry.addAttribute(new LdapAttribute("appEntityId", gsh_input_entityId)); ldapEntry.addAttribute(new LdapAttribute("appAdminEntitlement", "urn:mace:upenn.edu:" + adminsGroupName)); ldapEntry.addAttribute(new LdapAttribute("appOwnerEntitlement", "urn:mace:upenn.edu:" + ownersGroupName)); ldapEntry.addAttribute(new LdapAttribute("appDescription", gsh_input_description)); if (!StringUtils.equals("none", gsh_input_frontDoorPolicy) && !StringUtils.isBlank(gsh_input_frontDoorPolicy)) { ldapEntry.addAttribute(new LdapAttribute("appMACPolicy", gsh_input_frontDoorPolicy)); } ldapEntry.addAttribute(new LdapAttribute("appModifiedBy", subjectLoggedIn.getId())); ldapEntry.addAttribute(new LdapAttribute("appName", gsh_input_name)); if (!StringUtils.isBlank(inputPolicyGroupEntitlement)) { ldapEntry.addAttribute(new LdapAttribute("appPolicyGroup", inputPolicyGroupEntitlement)); } if (!StringUtils.isBlank(gsh_input_urlInstructions)) { ldapEntry.addAttribute(new LdapAttribute("appTestNote", gsh_input_urlInstructions)); } if (!StringUtils.isBlank(gsh_input_url)) { ldapEntry.addAttribute(new LdapAttribute("appTestURL", gsh_input_url)); } LdapSessionUtils.ldapSession().create(ldapConnection, ldapEntry); gsh_builtin_gshTemplateOutput.addOutputLine("Success: added a new service provider"); } else if (actionEdit) { Object[] dataRow = new GcDbAccess().sql("select name, description, url, url_instructions, " + "coarse_grained_policy, requires_twostep, error_page_type, error_page_url, error_page_text, front_door_policy_group from " + tableName + " where entity_id = ?").addBindVar(gsh_input_entityId). select(Object[].class); String name = (String)dataRow[0]; String description = (String)dataRow[1]; String url = (String)dataRow[2]; String urlInstructions = (String)dataRow[3]; String coarseGrainedPolicy = (String)dataRow[4]; String requiresTwoStep = (String)dataRow[5]; String errorPageType = (String)dataRow[6]; String errorPageUrl = (String)dataRow[7]; String errorPageText = (String)dataRow[8]; String frontDoorPolicyGroup = (String)dataRow[9]; String frontDoorPolicyGroupEntitlement = frontDoorPolicyGroup; if (!StringUtils.isBlank(frontDoorPolicyGroup)) { frontDoorPolicyGroupEntitlement = "urn:mace:upenn.edu:" + frontDoorPolicyGroup; } if (StringUtils.isBlank(coarseGrainedPolicy)) { coarseGrainedPolicy = "none"; } if (!isAdmin && !StringUtils.equals(frontDoorPolicyGroup, gsh_input_policyGroupName)) { gsh_builtin_gshTemplateOutput.addValidationLine("gsh_input_policyGroupName", "Non admins cannot change the policy group, contact ISC to change this"); return; } boolean hasChange = false; List<LdapModificationItem> ldapModificationItems = new ArrayList<LdapModificationItem>(); if (!StringUtils.equals(StringUtils.trimToNull(name), StringUtils.trimToNull(gsh_input_name))) { hasChange = true; createLdapModificationItem(ldapModificationItems, "appName", name, gsh_input_name); } if (!StringUtils.equals(StringUtils.trimToNull(description), StringUtils.trimToNull(gsh_input_description))) { hasChange = true; createLdapModificationItem(ldapModificationItems, "appDescription", description, gsh_input_description); } if (!StringUtils.equals(StringUtils.trimToNull(url), StringUtils.trimToNull(gsh_input_url))) { hasChange = true; createLdapModificationItem(ldapModificationItems, "appTestURL", url, gsh_input_url); } if (!StringUtils.equals(StringUtils.trimToNull(urlInstructions), StringUtils.trimToNull(gsh_input_urlInstructions))) { hasChange = true; createLdapModificationItem(ldapModificationItems, "appTestNote", urlInstructions, gsh_input_urlInstructions); } if (!StringUtils.equals(StringUtils.trimToNull(coarseGrainedPolicy), StringUtils.trimToNull(gsh_input_frontDoorPolicy))) { hasChange = true; createLdapModificationItem(ldapModificationItems, "appMACPolicy", StringUtils.equals(coarseGrainedPolicy, "none") ? null : coarseGrainedPolicy, StringUtils.equals(gsh_input_frontDoorPolicy, "none") ? null : gsh_input_frontDoorPolicy); } if (!StringUtils.equals(StringUtils.trimToNull(frontDoorPolicyGroupEntitlement), StringUtils.trimToNull(inputPolicyGroupEntitlement))) { hasChange = true; createLdapModificationItem(ldapModificationItems, "appPolicyGroup", frontDoorPolicyGroupEntitlement, inputPolicyGroupEntitlement); } String inputRequiresTwoStep = gsh_input_requiresTwostep ? "T" : "F"; if (!StringUtils.equals(StringUtils.trimToNull(requiresTwoStep), StringUtils.trimToNull(inputRequiresTwoStep))) { hasChange = true; } if (!StringUtils.equals(StringUtils.trimToNull(errorPageType), StringUtils.trimToNull(gsh_input_errorPageType))) { hasChange = true; } if (!StringUtils.equals(StringUtils.trimToNull(errorPageUrl), StringUtils.trimToNull(gsh_input_errorPageUrl))) { hasChange = true; } if (!StringUtils.equals(StringUtils.trimToNull(errorPageText), StringUtils.trimToNull(gsh_input_errorPageText))) { hasChange = true; } if (!hasChange) { gsh_builtin_gshTemplateOutput.addOutputLine("Note: no changes made"); return; } new GcDbAccess().sql("update " + tableName + " set name=?, description=?, url=?, url_instructions=?, coarse_grained_policy=?, " + "front_door_policy_group=?, requires_twostep=?, error_page_type=?, error_page_url=?, error_page_text=? where entity_id = ?"). addBindVar(gsh_input_name).addBindVar(gsh_input_description).addBindVar(gsh_input_url). addBindVar(gsh_input_urlInstructions).addBindVar(gsh_input_frontDoorPolicy).addBindVar(gsh_input_policyGroupName). addBindVar(inputRequiresTwoStep).addBindVar(gsh_input_errorPageType).addBindVar(gsh_input_errorPageUrl). addBindVar(gsh_input_errorPageText).addBindVar(gsh_input_entityId).executeSql(); if (ldapModificationItems.size() > 0) { createLdapModificationItem(ldapModificationItems, "appModifiedBy", "whatever123", subjectLoggedIn.getId()); // cn=c77a2c1fd25902a3e09e313af5cd4d0da29b7405,ou=applications,dc=penncommunity,dc=upenn,dc=edu String dn = "cn=" + entityIdShaHex + ",ou=applications,dc=authz,dc=upenn,dc=edu"; LdapSessionUtils.ldapSession().internal_modifyHelper(ldapConnection, dn, ldapModificationItems); } gsh_builtin_gshTemplateOutput.addOutputLine("Success: edited new service provider"); } else if (actionDelete) { if (adminsGroup != null) { adminsGroup.delete(); gsh_builtin_gshTemplateOutput.addOutputLine("Success: group deleted: " + adminsGroupName); } String ownersGroupName = "penn:isc:ts:iam:weblogin:service:policy:" + pennGroupsFolderExtension + ":service:policy:managers:" + groupExtensionOwners; Group ownersGroup = GroupFinder.findByName(ownersGroupName, false); if (ownersGroup != null) { ownersGroup.delete(); gsh_builtin_gshTemplateOutput.addOutputLine("Success: group deleted: " + ownersGroupName); } new GcDbAccess().sql("delete from " + tableName + " where entity_id = ?").addBindVar(gsh_input_entityId).executeSql(); gsh_builtin_gshTemplateOutput.addOutputLine("Success: delete registration in database for entity id: " + gsh_input_entityId); String dn = "cn=" + entityIdShaHex + ",ou=applications,dc=authz,dc=upenn,dc=edu"; LdapSessionUtils.ldapSession().delete(ldapConnection, dn); gsh_builtin_gshTemplateOutput.addOutputLine("Success: delete LDAP entry: " + dn); gsh_builtin_gshTemplateOutput.addOutputLine("Success: deleted the service provider"); } // if (StringUtils.equals("add", gsh_input_action)) { // // } else { // throw new RuntimeException("Invalid action: '" + gsh_input_action + "'"); // } } public static void main(String[] args) { GshTemplateV2input gshTemplateV2input = new GshTemplateV2input(); GshTemplateV2output gshTemplateV2output = new GshTemplateV2output(); GrouperSession.internal_callbackRootGrouperSession(new GrouperSessionHandler() { @Override public Object callback(GrouperSession grouperSession) throws GrouperSessionException { // user for chris hyzer //Subject subject = SubjectFinder.findByIdAndSource("10021368", "pennperson", true); // user for sam jenkins: 55308115 Subject subject = SubjectFinder.findByIdAndSource("55308115", "pennperson", true); gshTemplateV2input.setGsh_builtin_gshTemplateRuntime(new GshTemplateRuntime()); // gshTemplateV2input.getGsh_builtin_gshTemplateRuntime().setAuthenticatedSubject(subject); gshTemplateV2input.setGsh_builtin_subject(subject); gshTemplateV2input.getGsh_builtin_gshTemplateRuntime().setCurrentSubject(subject); GshTemplateRuntime gshTemplateRuntime = new GshTemplateRuntime(); gshTemplateRuntime.setTemplateConfigId("ssoCoarseGrainedAuthzConfig"); Test76ssoCoarseGrainedConfig myGshTemplate = new Test76ssoCoarseGrainedConfig(); gshTemplateV2input.getGsh_builtin_inputs().put("gsh_input_action", "add"); //gshTemplateV2input.getGsh_builtin_inputs().put("gsh_input_action", "edit"); //gshTemplateV2input.getGsh_builtin_inputs().put("gsh_input_entityId", "https://fides.isc-seo.upenn.edu/shibboleth"); //gshTemplateV2input.getGsh_builtin_inputs().put("gsh_input_name", "sdfsdf"); //gshTemplateV2input.getGsh_builtin_inputs().put("gsh_input_description", "sdfasdf"); //gshTemplateV2input.getGsh_builtin_inputs().put("gsh_input_admins", ""); //gshTemplateV2input.getGsh_builtin_inputs().put("gsh_input_owners", ""); //gshTemplateV2input.getGsh_builtin_inputs().put("gsh_input_frontDoorPolicy", "workforceInTwoStep"); //gshTemplateV2input.getGsh_builtin_inputs().put("gsh_input_url", ""); //gshTemplateV2input.getGsh_builtin_inputs().put("gsh_input_urlInstructions", ""); //gshTemplateV2input.getGsh_builtin_inputs().put("gsh_input_requiresTwostep", true); //myGshTemplate.gshRunLogic(gshTemplateV2input, gshTemplateV2output); // GshTemplateConfig templateConfig = new GshTemplateConfig("ssoCoarseGrainedAuthzConfig"); templateConfig.populateConfiguration(); GshTemplateDecorateForUiInput gshTemplateDecorateForUiInput = new GshTemplateDecorateForUiInput(); gshTemplateDecorateForUiInput.setOwnerStemName("penn:isc:ts:iam:weblogin:service:templates:idpRegistrationProd"); gshTemplateDecorateForUiInput.setCurrentSubject(subject); gshTemplateDecorateForUiInput.setEventConfigId("gsh_input_action"); Map<String, GshTemplateInputConfigAndValue> gshTemplateInputConfigAndValues = new HashMap<String, GshTemplateInputConfigAndValue>(); GshTemplateInputConfigAndValue gshTemplateConfigAndValue = gshTemplateConfigAndValue(); gshTemplateConfigAndValue.setGshTemplateInputConfig(templateConfig.getGshTemplateInputConfigs().get(0)); gshTemplateConfigAndValue.setValueObject("edit"); gshTemplateInputConfigAndValues.put("gsh_input_action", gshTemplateConfigAndValue); gshTemplateDecorateForUiInput.setGshTemplateInputConfigAndValues(gshTemplateInputConfigAndValues); myGshTemplate.decorateTemplateForUiDisplay(gshTemplateDecorateForUiInput); return null; } public GshTemplateInputConfigAndValue gshTemplateConfigAndValue() { return new GshTemplateInputConfigAndValue(); } }); System.out.println(GrouperUtil.toStringForLog(gshTemplateV2output.getGsh_builtin_gshTemplateOutput().getValidationLines())); System.out.println(GrouperUtil.toStringForLog(gshTemplateV2output.getGsh_builtin_gshTemplateOutput().getOutputLines())); System.exit(0); } }
Front door admin template
Used by IAM team for now to run reports
Config
grouperGshTemplate.ssoCoarseGrainedAuthz.defaultRunButtonFolderUuidOrName = penn\u003Aisc\u003Ats\u003Aiam\u003Aweblogin\u003Aservice\u003Atemplates\u003AidpRegistrationProd grouperGshTemplate.ssoCoarseGrainedAuthz.folderShowOnDescendants = certainFolders grouperGshTemplate.ssoCoarseGrainedAuthz.folderShowType = certainFolders grouperGshTemplate.ssoCoarseGrainedAuthz.folderUuidToShow = penn\u003Aisc\u003Ats\u003Aiam\u003Aweblogin\u003Aservice\u003Atemplates\u003AidpRegistrationProd grouperGshTemplate.ssoCoarseGrainedAuthz.groupUuidCanRun = penn\u003Aisc\u003Ats\u003Aiam\u003Aweblogin\u003Aservice\u003Asecurity\u003AcanRunIdpTemplate grouperGshTemplate.ssoCoarseGrainedAuthz.gshTemplate = // grouperGshTemplate.ssoCoarseGrainedAuthz.input.0.description = Select an action\u003A Analyze user access, Analyze user history, Analyze application grouperGshTemplate.ssoCoarseGrainedAuthz.input.0.dropdownCsvValue = Analyze application grouperGshTemplate.ssoCoarseGrainedAuthz.input.0.formElementType = dropdown grouperGshTemplate.ssoCoarseGrainedAuthz.input.0.label = Action grouperGshTemplate.ssoCoarseGrainedAuthz.input.0.name = gsh_input_action grouperGshTemplate.ssoCoarseGrainedAuthz.input.1.description = Enter in the SAML entity ID (you can get this from Firefox SAML tracer plugin) grouperGshTemplate.ssoCoarseGrainedAuthz.input.1.dropdownValueFormat = dynamicFromTemplate grouperGshTemplate.ssoCoarseGrainedAuthz.input.1.formElementType = dropdown grouperGshTemplate.ssoCoarseGrainedAuthz.input.1.label = SAML entity ID grouperGshTemplate.ssoCoarseGrainedAuthz.input.1.name = gsh_input_samlEntityId grouperGshTemplate.ssoCoarseGrainedAuthz.input.1.required = true grouperGshTemplate.ssoCoarseGrainedAuthz.input.1.showEl = \u0024{gsh_input_action == 'Analyze application' || gsh_input_action == 'Analyze user access'} grouperGshTemplate.ssoCoarseGrainedAuthz.input.2.description = Enter the PennKey or PennID of the user grouperGshTemplate.ssoCoarseGrainedAuthz.input.2.label = PennKey or Penn ID grouperGshTemplate.ssoCoarseGrainedAuthz.input.2.name = gsh_input_pennkey grouperGshTemplate.ssoCoarseGrainedAuthz.input.2.showEl = \u0024{gsh_input_action == 'Analyze user access' || gsh_input_action == 'Analyze user history'} grouperGshTemplate.ssoCoarseGrainedAuthz.input.2.validationType = none grouperGshTemplate.ssoCoarseGrainedAuthz.input.3.description = SAML entity ID (you can get this from Firefox SAML tracer plugin) grouperGshTemplate.ssoCoarseGrainedAuthz.input.3.dropdownValueFormat = dynamicFromTemplate grouperGshTemplate.ssoCoarseGrainedAuthz.input.3.formElementType = dropdown grouperGshTemplate.ssoCoarseGrainedAuthz.input.3.label = SAML entity ID grouperGshTemplate.ssoCoarseGrainedAuthz.input.3.name = gsh_input_samlEntityIdForUser grouperGshTemplate.ssoCoarseGrainedAuthz.input.3.showEl = \u0024{false} grouperGshTemplate.ssoCoarseGrainedAuthz.moreActionsLabel = WebLogin front door authorization grouperGshTemplate.ssoCoarseGrainedAuthz.numberOfInputs = 4 grouperGshTemplate.ssoCoarseGrainedAuthz.runAsType = GrouperSystem grouperGshTemplate.ssoCoarseGrainedAuthz.runButtonGroupOrFolder = folder grouperGshTemplate.ssoCoarseGrainedAuthz.securityRunType = specifiedGroup grouperGshTemplate.ssoCoarseGrainedAuthz.showInMoreActions = true grouperGshTemplate.ssoCoarseGrainedAuthz.showOnFolders = true grouperGshTemplate.ssoCoarseGrainedAuthz.templateDescription = Analyze a service provider (application) or a user in front door authorization in WebLogin grouperGshTemplate.ssoCoarseGrainedAuthz.templateName = WebLogin front door authorization grouperGshTemplate.ssoCoarseGrainedAuthz.templateType = gsh grouperGshTemplate.ssoCoarseGrainedAuthz.templateVersion = V2
Code
import java.io.File; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.lang3.StringUtils; import edu.internet2.middleware.grouper.GrouperSession; import edu.internet2.middleware.grouper.SubjectFinder; import edu.internet2.middleware.grouper.app.gsh.template.GshTemplateDecorateForUiInput; import edu.internet2.middleware.grouper.app.gsh.template.GshTemplateInputConfigAndValue; import edu.internet2.middleware.grouper.app.gsh.template.GshTemplateOutput; import edu.internet2.middleware.grouper.app.gsh.template.GshTemplateRuntime; import edu.internet2.middleware.grouper.app.gsh.template.GshTemplateV2; import edu.internet2.middleware.grouper.app.gsh.template.GshTemplateV2input; import edu.internet2.middleware.grouper.app.gsh.template.GshTemplateV2output; import edu.internet2.middleware.grouper.app.reports.GrouperCsvReportJob; import edu.internet2.middleware.grouper.exception.GrouperSessionException; import edu.internet2.middleware.grouper.misc.GrouperSessionHandler; import edu.internet2.middleware.grouper.util.GrouperEmail; import edu.internet2.middleware.grouper.util.GrouperEmailUtils; import edu.internet2.middleware.grouper.util.GrouperUtil; import edu.internet2.middleware.grouperClient.collections.MultiKey; import edu.internet2.middleware.grouperClient.jdbc.GcDbAccess; import edu.internet2.middleware.subject.Subject; public class Test76ssoCoarseGrained extends GshTemplateV2 { public static class TheState { Map<String, Map<String, List<Object[]>>> groupNameToPennIdToPointInTime = new HashMap<>(); // get point in time per bucket and per user // buckets are: // inTwoStep: penn:isc:ts:iam:weblogin:service:policy:idpCoarseGrained:enrolledInTwoStep // affiliate: penn:isc:ts:iam:weblogin:service:policy:idpCoarseGrained:idpAffiliate // affiliateInTwoStep: penn:isc:ts:iam:weblogin:service:policy:idpCoarseGrained:idpAffiliateInTwoStep // member: penn:isc:ts:iam:weblogin:service:policy:idpCoarseGrained:member // memberInTwoStep: penn:isc:ts:iam:weblogin:service:policy:idpCoarseGrained:memberInTwoStep // employeeInTwoStep: penn:isc:ts:iam:weblogin:service:policy:idpCoarseGrained:employeesInTwoStep Map<String, String> bucketLabelToGroupName = GrouperUtil.toMap( "inTwoStep", "penn:isc:ts:iam:weblogin:service:policy:idpCoarseGrained:enrolledInTwoStep", "affiliate", "penn:isc:ts:iam:weblogin:service:policy:idpCoarseGrained:idpAffiliate", "affiliateInTwoStep", "penn:isc:ts:iam:weblogin:service:policy:idpCoarseGrained:idpAffiliateInTwoStep", "member", "penn:isc:ts:iam:weblogin:service:policy:idpCoarseGrained:member", "memberInTwoStep", "penn:isc:ts:iam:weblogin:service:policy:idpCoarseGrained:memberInTwoStep", "employeeInTwoStep", "penn:isc:ts:iam:weblogin:service:policy:idpCoarseGrained:employeesInTwoStep"); Map<String, String> groupNameToBucketLabel = new HashMap<>(); String deprovisionedGroupName = "penn:etc:deprovisioning:usersWhoHaveBeenDeprovisioned_employee"; public TheState() { for (String bucketLabel : bucketLabelToGroupName.keySet()) { groupNameToBucketLabel.put(bucketLabelToGroupName.get(bucketLabel), bucketLabel); } } } private static int percent(int count, int total) { if (total == 0 || count == 0) { return 0; } int percent = (int)Math.round((100d * (double)count / (double)total)); if (percent == 100 && count != total) { percent = 99; } return percent; } @Override public void gshRunLogic(GshTemplateV2input gshTemplateV2input, GshTemplateV2output gshTemplateV2output) { TheState theState = new TheState(); // Analyze user access, Analyze user history, Analyze application String gsh_input_action = gshTemplateV2input.getGsh_builtin_inputString("gsh_input_action"); GshTemplateOutput gsh_builtin_gshTemplateOutput = gshTemplateV2output.getGsh_builtin_gshTemplateOutput(); Subject currentUserSubject = gshTemplateV2input.getGsh_builtin_subject(); if (StringUtils.equals("Analyze application", gsh_input_action)) { String gsh_input_samlEntityId = gshTemplateV2input.getGsh_builtin_inputString("gsh_input_samlEntityId"); String sql = """ select spefd.name_without_special_characters, spefd."name", spefd.description, spefd.url, spefd.url_instructions, spefd.coarse_grained_policy, spefd.front_door_policy_group, spefd.error_page_type, spefd.error_page_text, spefd.error_page_url from sso_prod_entity_front_door spefd where spefd.entity_id=? """; Object[] frontDoorConfig = new GcDbAccess().sql(sql).addBindVar(gsh_input_samlEntityId).select(Object[].class); String nameWithoutSpecialChars = gsh_input_samlEntityId == null ? null : gsh_input_samlEntityId.replaceAll("[^A-Za-z0-9_-]", "_"); if (GrouperUtil.length(frontDoorConfig) == 0) { gsh_builtin_gshTemplateOutput.addOutputLine("The service provider does not have a front door config."); gsh_builtin_gshTemplateOutput.addOutputLine(" "); } else { nameWithoutSpecialChars = (String)frontDoorConfig[0]; String name = (String)frontDoorConfig[1]; String description = (String)frontDoorConfig[2]; String url = (String)frontDoorConfig[3]; String urlInstructions = (String)frontDoorConfig[4]; String coarseGrainedPolicy = (String)frontDoorConfig[5]; String frontDoorPolicyGroup = (String)frontDoorConfig[6]; String errorPageType = (String)frontDoorConfig[7]; String errorPageText = (String)frontDoorConfig[8]; String errorPageUrl = (String)frontDoorConfig[9]; gsh_builtin_gshTemplateOutput.addOutputLine("The service provider has a front door config."); gsh_builtin_gshTemplateOutput.addOutputLine("App name: " + GrouperUtil.escapeHtml(name, true)); gsh_builtin_gshTemplateOutput.addOutputLine("Description: " + GrouperUtil.escapeHtml(description, true)); gsh_builtin_gshTemplateOutput.addOutputLine("URL: <a href=\"" + GrouperUtil.escapeHtml(url, true) + "\">" + GrouperUtil.escapeHtml(url, true) + "</a>"); gsh_builtin_gshTemplateOutput.addOutputLine("Login instructions: " + GrouperUtil.escapeHtml(urlInstructions, true)); gsh_builtin_gshTemplateOutput.addOutputLine("Coarse grained policy: " + GrouperUtil.escapeHtml(coarseGrainedPolicy, true)); if (!StringUtils.isBlank(frontDoorPolicyGroup)) { gsh_builtin_gshTemplateOutput.addOutputLine("Front door group: " + GrouperUtil.escapeHtml(frontDoorPolicyGroup, true)); } gsh_builtin_gshTemplateOutput.addOutputLine("Error page type: " + GrouperUtil.escapeHtml(errorPageType, true)); if (!StringUtils.isBlank(errorPageText)) { gsh_builtin_gshTemplateOutput.addOutputLine("Error page text: " + GrouperUtil.escapeHtml(errorPageText, true)); } if (!StringUtils.isBlank(errorPageUrl)) { gsh_builtin_gshTemplateOutput.addOutputLine("Error page URL: " + GrouperUtil.escapeHtml(errorPageUrl, true)); } gsh_builtin_gshTemplateOutput.addOutputLine(" "); } sql = """ select penn_id, person_description, login_timestamp, pennkey, two_step_enrolled, workforce, member, affiliate, recent_affiliate, alum_or_affiliate, uphs_only, alum_only, in_front_door, locked_out, non_persistent, uphs_not_pennpay_not_student, email, coarse_grained_group_name, now_two_step, now_workforce, now_member, now_affliate, now_recent_affliate, now_affliate_or_alum, now_locked_out, now_in_front_door_group_current, entity_id, login_timestamp_native from sso_prod_logs_v where entity_id = ? order by login_timestamp_native desc """; List<Object[]> ssoProdLogs = new GcDbAccess().sql(sql).addBindVar(gsh_input_samlEntityId).selectList(Object[].class); List<String> reportHeaders = GrouperUtil.toList( "penn_id", "person_description", "login_timestamp", "pennkey", "login_two_step_enrolled", "login_workforce", "login_member", "login_affiliate", "login_recent_affiliate", "login_alum_or_affiliate", "login_uphs_only", "login_alum_only", "login_in_front_door", "login_locked_out", "non_persistent", "uphs_not_pennpay_not_student", "email", "coarse_grained_group_name", "now_two_step", "now_workforce", "now_member", "now_affliate", "now_recent_affliate", "now_affliate_or_alum", "now_locked_out", "now_in_front_door_group_current", "entity_id"); List<String[]> reportData = new ArrayList<String[]>(); Timestamp minTimestamp = null; Set<String> pennIds = new HashSet<String>(); Set<String> pennIdsWorkforce = new HashSet<String>(); Set<String> pennIdsNotWorkforce = new HashSet<String>(); Set<String> pennIdsWorkforceOrAreNow = new HashSet<String>(); int workforceCount = 0; int workforceOrIsNowCount = 0; Set<String> pennIdsTwostep = new HashSet<String>(); Set<String> pennIdsNotTwostep = new HashSet<String>(); Set<String> pennIdsTwostepOrAreNow = new HashSet<String>(); int twostepCount = 0; int twostepOrIsNowCount = 0; Set<String> pennIdsMember = new HashSet<String>(); Set<String> pennIdsNotMember = new HashSet<String>(); Set<String> pennIdsMemberOrAreNow = new HashSet<String>(); int memberCount = 0; int memberOrIsNowCount = 0; Set<String> pennIdsAffiliate = new HashSet<String>(); Set<String> pennIdsNotAffiliate = new HashSet<String>(); Set<String> pennIdsAffiliateOrAreNow = new HashSet<String>(); int affiliateCount = 0; int affiliateOrIsNowCount = 0; Set<String> pennIdsAffiliateOrAlum = new HashSet<String>(); Set<String> pennIdsNotAffiliateOrAlum = new HashSet<String>(); Set<String> pennIdsAffiliateOrAlumOrAreNow = new HashSet<String>(); int affiliateOrAlumCount = 0; int affiliateOrAlumOrIsNowCount = 0; Set<String> pennIdsRecentAffiliate = new HashSet<String>(); Set<String> pennIdsNotRecentAffiliate = new HashSet<String>(); Set<String> pennIdsRecentAffiliateOrAreNow = new HashSet<String>(); int recentAffiliateCount = 0; int recentAffiliateOrIsNowCount = 0; Set<MultiKey> usersLogged = new HashSet<MultiKey>(); for (Object[] ssoProdLog : ssoProdLogs) { String pennId = (String)ssoProdLog[0]; pennIds.add(pennId); String personDescription = (String)ssoProdLog[1]; String loginTimestamp = (String)ssoProdLog[2]; String pennkey = (String)ssoProdLog[3]; String twoStepEnrolled = (String)ssoProdLog[4]; String workforce = (String)ssoProdLog[5]; String member = (String)ssoProdLog[6]; String affiliate = (String)ssoProdLog[7]; String recentAffiliate = (String)ssoProdLog[8]; String alumOrAffiliate = (String)ssoProdLog[9]; String uphsOnly = (String)ssoProdLog[10]; String alumOnly = (String)ssoProdLog[11]; String inFrontDoor = (String)ssoProdLog[12]; String lockedOut = (String)ssoProdLog[13]; String nonPersistent = (String)ssoProdLog[14]; String uphsNotPennpayNotStudent = (String)ssoProdLog[15]; String email = (String)ssoProdLog[16]; String coarseGrainedGroupName = (String)ssoProdLog[17]; String nowTwoStep = (String)ssoProdLog[18]; if (StringUtils.equals("T", twoStepEnrolled)) { pennIdsTwostep.add(pennId); twostepCount++; pennIdsTwostepOrAreNow.add(pennId); twostepOrIsNowCount++; } else { pennIdsNotTwostep.add(pennId); if (StringUtils.equals("T", nowTwoStep)) { pennIdsTwostepOrAreNow.add(pennId); twostepOrIsNowCount++; } } String nowWorkforce = (String)ssoProdLog[19]; if (StringUtils.equals("T", workforce)) { pennIdsWorkforce.add(pennId); workforceCount++; pennIdsWorkforceOrAreNow.add(pennId); workforceOrIsNowCount++; } else { pennIdsNotWorkforce.add(pennId); if (StringUtils.equals("T", nowWorkforce)) { pennIdsWorkforceOrAreNow.add(pennId); workforceOrIsNowCount++; } } String nowMember = (String)ssoProdLog[20]; if (StringUtils.equals("T", member)) { pennIdsMember.add(pennId); memberCount++; pennIdsMemberOrAreNow.add(pennId); memberOrIsNowCount++; } else { pennIdsNotMember.add(pennId); if (StringUtils.equals("T", nowMember)) { pennIdsMemberOrAreNow.add(pennId); memberOrIsNowCount++; } } String nowAffiliate = (String)ssoProdLog[21]; if (StringUtils.equals("T", affiliate)) { pennIdsAffiliate.add(pennId); affiliateCount++; pennIdsAffiliateOrAreNow.add(pennId); affiliateOrIsNowCount++; } else { pennIdsNotAffiliate.add(pennId); if (StringUtils.equals("T", nowAffiliate)) { pennIdsAffiliateOrAreNow.add(pennId); affiliateOrIsNowCount++; } } String nowRecentAffiliate = (String)ssoProdLog[22]; if (StringUtils.equals("T", recentAffiliate)) { pennIdsRecentAffiliate.add(pennId); recentAffiliateCount++; pennIdsRecentAffiliateOrAreNow.add(pennId); recentAffiliateOrIsNowCount++; } else { pennIdsNotRecentAffiliate.add(pennId); if (StringUtils.equals("T", nowRecentAffiliate)) { pennIdsRecentAffiliateOrAreNow.add(pennId); recentAffiliateOrIsNowCount++; } } String nowAffliateOrAlum = (String)ssoProdLog[23]; if (StringUtils.equals("T", alumOrAffiliate)) { pennIdsAffiliateOrAlum.add(pennId); affiliateOrAlumCount++; pennIdsAffiliateOrAlumOrAreNow.add(pennId); affiliateOrAlumOrIsNowCount++; } else { pennIdsNotAffiliateOrAlum.add(pennId); if (StringUtils.equals("T", nowAffliateOrAlum)) { pennIdsAffiliateOrAlumOrAreNow.add(pennId); affiliateOrAlumOrIsNowCount++; } } String nowLockedOut = (String)ssoProdLog[24]; String nowInFrontDoorGroupCurrent = (String)ssoProdLog[25]; String entityId = (String)ssoProdLog[26]; Timestamp timestamp = GrouperUtil.toTimestamp(ssoProdLog[27]); if (minTimestamp == null || timestamp.getTime() < minTimestamp.getTime()) { minTimestamp = timestamp; } if (ssoProdLogs.size() >= 30000) { MultiKey userLogged = new MultiKey(GrouperUtil.toArrayObject(pennId, twoStepEnrolled, workforce, member, affiliate, alumOrAffiliate, recentAffiliate)); if (usersLogged.contains(userLogged)) { continue; } usersLogged.add(userLogged); } String[] reportDataRow = GrouperUtil.toArray(GrouperUtil.toList(pennId, personDescription, loginTimestamp, pennkey, twoStepEnrolled, workforce, member, affiliate, recentAffiliate, alumOrAffiliate, uphsOnly, alumOnly, inFrontDoor, lockedOut, nonPersistent, uphsNotPennpayNotStudent, email, coarseGrainedGroupName, nowTwoStep, nowWorkforce, nowMember, nowAffiliate, nowRecentAffiliate, nowAffliateOrAlum, nowLockedOut, nowInFrontDoorGroupCurrent, entityId), String.class); reportData.add(reportDataRow); } if (reportData.size() > 30000) { Iterator<String[]> iterator = reportData.iterator(); int count = 0; while (iterator.hasNext()) { String[] reportDataRow = iterator.next(); if (StringUtils.equals("T", reportDataRow[4]) && StringUtils.equals("T", reportDataRow[5])) { iterator.remove(); continue; } if (count >= 30000) { iterator.remove(); continue; } count++; } } String timestampToFileString = GrouperUtil.timestampToFileString(new Date()); String fileName = GrouperUtil.tmpDir(true) + "spLogs_" + nameWithoutSpecialChars + "_" + timestampToFileString + ".csv"; File file = GrouperCsvReportJob.createCsv(fileName, reportHeaders, reportData); new GrouperEmail().addEmailAddressToSendTo(GrouperEmailUtils.getEmail(currentUserSubject)). setSubject("SP report for " + gsh_input_samlEntityId + ": " + timestampToFileString). setBody("Attached is " + gsh_input_samlEntityId + " report").addAttachment(file).send(); file.delete(); gsh_builtin_gshTemplateOutput.addOutputLine("The user report was emailed to you" + (reportData.size() != ssoProdLogs.size() ? (", note " + (ssoProdLogs.size() - reportData.size()) + " old or redundant or twostep/workforce rows were removed") : "")); gsh_builtin_gshTemplateOutput.addOutputLine(" "); gsh_builtin_gshTemplateOutput.addOutputLine("There were " + pennIds.size() + " users and " + ssoProdLogs.size() + " log-ins since " + minTimestamp + "."); gsh_builtin_gshTemplateOutput.addOutputLine("For two-step: " + (pennIds.size()-pennIdsNotTwostep.size()) + "/" + pennIds.size() + " users (" + percent(pennIds.size()-pennIdsNotTwostep.size(), pennIds.size()) + "%), " + pennIdsTwostepOrAreNow.size() + "/" + pennIds.size() + " users or now (" + percent(pennIdsTwostepOrAreNow.size(), pennIds.size()) + "%), " + twostepCount + "/" + ssoProdLogs.size() + " log ins (" + percent(twostepCount, ssoProdLogs.size()) + "%), " + twostepOrIsNowCount + "/" + ssoProdLogs.size() + " log ins or now (" + percent(twostepOrIsNowCount, ssoProdLogs.size()) + "%)"); gsh_builtin_gshTemplateOutput.addOutputLine("For workforce: " + (pennIds.size()-pennIdsNotWorkforce.size()) + "/" + pennIds.size() + " users (" + percent(pennIds.size()-pennIdsNotWorkforce.size(), pennIds.size()) + "%), " + pennIdsWorkforceOrAreNow.size() + "/" + pennIds.size() + " users or now (" + percent(pennIdsWorkforceOrAreNow.size(), pennIds.size()) + "%), " + workforceCount + "/" + ssoProdLogs.size() + " log ins (" + percent(workforceCount, ssoProdLogs.size()) + "%), " + workforceOrIsNowCount + "/" + ssoProdLogs.size() + " log ins or now (" + percent(workforceOrIsNowCount, ssoProdLogs.size()) + "%)"); gsh_builtin_gshTemplateOutput.addOutputLine("For member: " + (pennIds.size() - pennIdsNotMember.size()) + "/" + pennIds.size() + " users (" + percent(pennIds.size() - pennIdsNotMember.size(), pennIds.size()) + "%), " + pennIdsMemberOrAreNow.size() + "/" + pennIds.size() + " users or now (" + percent(pennIdsMemberOrAreNow.size(), pennIds.size()) + "%), " + memberCount + "/" + ssoProdLogs.size() + " log ins (" + percent(memberCount, ssoProdLogs.size()) + "%), " + memberOrIsNowCount + "/" + ssoProdLogs.size() + " log ins or now (" + percent(memberOrIsNowCount, ssoProdLogs.size()) + "%)"); gsh_builtin_gshTemplateOutput.addOutputLine("For affiliate: " + (pennIds.size()-pennIdsNotAffiliate.size()) + "/" + pennIds.size() + " users (" + percent(pennIds.size()-pennIdsNotAffiliate.size(), pennIds.size()) + "%), " + pennIdsAffiliateOrAreNow.size() + "/" + pennIds.size() + " users or now (" + percent(pennIdsAffiliateOrAreNow.size(), pennIds.size()) + "%), " + affiliateCount + "/" + ssoProdLogs.size() + " log ins (" + percent(affiliateCount, ssoProdLogs.size()) + "%), " + affiliateOrIsNowCount + "/" + ssoProdLogs.size() + " log ins or now (" + percent(affiliateOrIsNowCount, ssoProdLogs.size()) + "%)"); gsh_builtin_gshTemplateOutput.addOutputLine("For affiliateOrAlum: " + (pennIds.size()-pennIdsNotAffiliateOrAlum.size()) + "/" + pennIds.size() + " users (" + percent(pennIds.size()-pennIdsNotAffiliateOrAlum.size(), pennIds.size()) + "%), " + pennIdsAffiliateOrAlumOrAreNow.size() + "/" + pennIds.size() + " users or now (" + percent(pennIdsAffiliateOrAlumOrAreNow.size(), pennIds.size()) + "%), " + affiliateOrAlumCount + "/" + ssoProdLogs.size() + " log ins (" + percent(affiliateOrAlumCount, ssoProdLogs.size()) + "%), " + affiliateOrAlumOrIsNowCount + "/" + ssoProdLogs.size() + " log ins or now (" + percent(affiliateOrAlumOrIsNowCount, ssoProdLogs.size()) + "%)"); gsh_builtin_gshTemplateOutput.addOutputLine("For recentAffiliate: " + (pennIds.size()-pennIdsNotRecentAffiliate.size()) + "/" + pennIds.size() + " users (" + percent(pennIds.size()-pennIdsNotRecentAffiliate.size(), pennIds.size()) + "%), " + pennIdsRecentAffiliateOrAreNow.size() + "/" + pennIds.size() + " users or now (" + percent(pennIdsRecentAffiliateOrAreNow.size(), pennIds.size()) + "%), " + recentAffiliateCount + "/" + ssoProdLogs.size() + " log ins (" + percent(recentAffiliateCount, ssoProdLogs.size()) + "%), " + recentAffiliateOrIsNowCount + "/" + ssoProdLogs.size() + " log ins or now (" + percent(recentAffiliateOrIsNowCount, ssoProdLogs.size()) + "%)"); } else if (StringUtils.equals("Analyze user history", gsh_input_action)) { String gsh_input_pennkey = gshTemplateV2input.getGsh_builtin_inputString("gsh_input_pennkey"); Subject subject = SubjectFinder.findByIdOrIdentifierAndSource(gsh_input_pennkey, "pennperson", false); if (subject == null) { gsh_builtin_gshTemplateOutput.addValidationLine("gsh_input_pennkey", "Cannot find person"); return; } List<Object[]> entityIdAndTimestamps = new GcDbAccess().sql( "select entity_id, login_timestamp from sso_prod_logs_v splv where penn_id = ? order by login_timestamp desc"). addBindVar(subject.getId()).selectList(Object[].class); Set<String> entityIds = new LinkedHashSet<>(); for (Object[] entityIdAndTimestamp : entityIdAndTimestamps) { String entityId = (String)entityIdAndTimestamp[0]; Timestamp timestamp = (Timestamp)entityIdAndTimestamp[1]; if (entityIds.contains(entityId)) { continue; } entityIds.add(entityId); } Set<String> groupNames = new HashSet<String>(theState.bucketLabelToGroupName.values()); groupNames.add(theState.deprovisionedGroupName); for (String groupName : groupNames) { GcDbAccess gcDbAccess = new GcDbAccess(); gcDbAccess.sql("select gpmglv.subject_id, gpmglv.the_start_time, gpmglv.the_end_time from grouper_pit_mship_group_lw_v gpmglv " + " where gpmglv.subject_id = ? " + " and gpmglv.subject_source = 'pennperson' " + " and gpmglv.field_name = 'members' " + " and gpmglv.group_name = ? "); gcDbAccess.addBindVar(subject.getId()); gcDbAccess.addBindVar(groupName); List<Object[]> pennIdStartEnds = gcDbAccess.selectList(Object[].class); for (Object[] pennIdStartEnd : pennIdStartEnds) { String pennId = (String)pennIdStartEnd[0]; Long startMillis = GrouperUtil.longValue(pennIdStartEnd[1]); if (startMillis != null) { startMillis /= 1000; } Long endMillis = GrouperUtil.longObjectValue(pennIdStartEnd[2], true); if (endMillis != null) { endMillis /= 1000; } Map<String, List<Object[]>> pennIdToStartAndEnd = theState.groupNameToPennIdToPointInTime.get(groupName); if (pennIdToStartAndEnd == null) { pennIdToStartAndEnd = new HashMap<>(); theState.groupNameToPennIdToPointInTime.put(groupName, pennIdToStartAndEnd); } List<Object[]> startMillisEndMillises = pennIdToStartAndEnd.get(pennId); if (startMillisEndMillises == null) { startMillisEndMillises = new ArrayList<Object[]>(); pennIdToStartAndEnd.put(pennId, startMillisEndMillises); } startMillisEndMillises.add(GrouperUtil.toArrayObject(startMillis, endMillis)); } } gsh_builtin_gshTemplateOutput.addOutputLine(subject.getDescription()); String pennId = subject.getId(); // non persistent if (pennId.startsWith("9")) { gsh_builtin_gshTemplateOutput.addOutputLine("User is non-persistent"); } else { gsh_builtin_gshTemplateOutput.addOutputLine("User not from a non-persistent affiliation"); } boolean isLockedOut = isInGroup(theState, theState.deprovisionedGroupName, pennId, System.currentTimeMillis()); if (isLockedOut) { gsh_builtin_gshTemplateOutput.addOutputLine("User is locked out"); } else { gsh_builtin_gshTemplateOutput.addOutputLine("User not locked out"); } for (String bucket : theState.bucketLabelToGroupName.keySet()) { boolean isInBucket = isInGroup(theState, bucket, pennId, System.currentTimeMillis()); if (isInBucket) { gsh_builtin_gshTemplateOutput.addOutputLine("User is in built-in population: " + bucket); } else { gsh_builtin_gshTemplateOutput.addOutputLine("User is not in built-in population: " + bucket); } } for (String entityId : entityIds) { gsh_builtin_gshTemplateOutput.addOutputLine("Entity id '" + entityId + "':"); for (Object[] entityIdAndTimestamp : entityIdAndTimestamps) { String currentEntityId = (String)entityIdAndTimestamp[0]; Timestamp timestamp = (Timestamp)entityIdAndTimestamp[1]; if (!StringUtils.equals(entityId, currentEntityId)) { continue; } //TODO put in success or not gsh_builtin_gshTemplateOutput.addOutputLine("Authenticated " + timestamp.toString()); } } } else if (StringUtils.equals("Analyze user access", gsh_input_action)) { String gsh_input_pennkey = gshTemplateV2input.getGsh_builtin_inputString("gsh_input_pennkey"); String gsh_input_samlEntityIdForUser = gshTemplateV2input.getGsh_builtin_inputString("gsh_input_samlEntityIdForUser"); gsh_builtin_gshTemplateOutput.addOutputLine("The service provider uses the coarse grained authorization group 'ISC employees in Two-step'."); if (StringUtils.equals("mchyzer", gsh_input_pennkey)) { gsh_builtin_gshTemplateOutput.addOutputLine("The user is currently in the coarse-grained authz group: penn:isc:ts:iam:weblogin:service:policy:idpCoarseGrained:iscEmployeesInTwoStep"); gsh_builtin_gshTemplateOutput.addOutputLine("The user has been in the group since 2024-01-12 1:43 pm"); gsh_builtin_gshTemplateOutput.addOutputLine("The user has authenticated to the service 9 times in the last week"); gsh_builtin_gshTemplateOutput.addOutputLine("Recent successful authentication time: 2024-01-22 10:12 am"); gsh_builtin_gshTemplateOutput.addOutputLine("Recent successful authentication time: 2024-01-22 8:45 am"); gsh_builtin_gshTemplateOutput.addOutputLine("Recent successful authentication time: 2024-01-21 7:32 pm"); } if (StringUtils.equals("isobel", gsh_input_pennkey)) { gsh_builtin_gshTemplateOutput.addOutputLine("The user is currently not in the coarse-grained authz group: penn:isc:ts:iam:weblogin:service:policy:idpCoarseGrained:iscEmployeesInTwoStep"); gsh_builtin_gshTemplateOutput.addOutputLine("The user was in the group between 2023-05-12 1:43 pm - 2023-12-03 5:51 pm"); gsh_builtin_gshTemplateOutput.addOutputLine("The user has authenticated to the service 5 times in the last week"); gsh_builtin_gshTemplateOutput.addOutputLine("Recent successful authentication time: 2024-01-22 8:12 am"); gsh_builtin_gshTemplateOutput.addOutputLine("Recent unsuccessful authentication time: 2024-01-19 5:45 am"); gsh_builtin_gshTemplateOutput.addOutputLine("Recent unsuccessful authentication time: 2024-01-15 4:32 pm"); } } else { throw new RuntimeException("Invalid action: '" + gsh_input_action + "'"); } gsh_builtin_gshTemplateOutput.assignRedirectToGrouperOperation("NONE"); } public static void main(String[] args) { GshTemplateV2input gshTemplateV2input = new GshTemplateV2input(); GshTemplateV2output gshTemplateV2output = new GshTemplateV2output(); GrouperSession.internal_callbackRootGrouperSession(new GrouperSessionHandler() { @Override public Object callback(GrouperSession grouperSession) throws GrouperSessionException { Subject subject = SubjectFinder.findByIdAndSource("10021368", "pennperson", true); gshTemplateV2input.setGsh_builtin_subject(subject); GshTemplateRuntime gshTemplateRuntime = new GshTemplateRuntime(); gshTemplateRuntime.setTemplateConfigId("ssoCoarseGrainedAuthz"); Test76ssoCoarseGrained myGshTemplate = new Test76ssoCoarseGrained(); //gshTemplateV2input.getGsh_builtin_inputs().put("gsh_input_action", "Analyze user history"); gshTemplateV2input.getGsh_builtin_inputs().put("gsh_input_action", "Analyze application"); gshTemplateV2input.getGsh_builtin_inputs().put("gsh_input_samlEntityId", "https://upenndar-compass.my.salesforce.com"); gshTemplateV2input.getGsh_builtin_inputs().put("gsh_input_pennkey", "mchyzer"); myGshTemplate.gshRunLogic(gshTemplateV2input, gshTemplateV2output); return null; } }); System.out.println(GrouperUtil.toStringForLog(gshTemplateV2output.getGsh_builtin_gshTemplateOutput().getValidationLines())); System.out.println(GrouperUtil.toStringForLog(gshTemplateV2output.getGsh_builtin_gshTemplateOutput().getOutputLines())); System.exit(0); } @Override public void decorateTemplateForUiDisplay(GshTemplateDecorateForUiInput gshTemplateDecorateForUiInput) { String stemName = gshTemplateDecorateForUiInput.getOwnerStemName(); boolean prod = StringUtils.equals(stemName, "penn:isc:ts:iam:weblogin:service:templates:idpRegistrationProd"); if (!stemName.startsWith("penn:isc:ts:iam:weblogin:service:templates:")) { throw new RuntimeException("Invalid owner folder, should start with: 'penn:isc:ts:iam:weblogin:service:templates:'"); } String tableName = "sso_stage_entity_front_door"; if (prod) { tableName = "sso_prod_entity_front_door"; } GshTemplateInputConfigAndValue dropDownConfigAndValueAction = gshTemplateDecorateForUiInput.getGshTemplateInputConfigAndValues().get("gsh_input_action"); GshTemplateInputConfigAndValue dropDownConfigAndValueEntityId = gshTemplateDecorateForUiInput.getGshTemplateInputConfigAndValues().get("gsh_input_samlEntityId"); if (StringUtils.equalsAny(dropDownConfigAndValueAction.getValue(), "Analyze application", "Analyze user access")) { List<String> entityIds = new GcDbAccess().sql("select entity_id from sso_prod_entity_id spei order by 1").selectList(String.class); List<MultiKey> keysAndValues = new ArrayList<MultiKey>(); keysAndValues.add(new MultiKey("", "")); for (String entityId : entityIds) { keysAndValues.add(new MultiKey(entityId, entityId)); } dropDownConfigAndValueEntityId.getGshTemplateInputConfig().setDropdownKeysAndLabels(keysAndValues); } if (gshTemplateDecorateForUiInput.isSubmit()) { String gsh_input_action = dropDownConfigAndValueAction.getValue(); if (StringUtils.equals("Analyze user history", gsh_input_action) || StringUtils.equals("Analyze user access", gsh_input_action)) { // GshTemplateInputConfigAndValue dropDownConfigAndValue = gshTemplateDecorateForUiInput.getGshTemplateInputConfigAndValues().get("gsh_input_samlEntityIdForUser"); // List<MultiKey> localDropdownKeysAndLabels = new ArrayList<MultiKey>(); // localDropdownKeysAndLabels.add(new MultiKey("flash", "value1")); } } // // dynamically set the options for drop down 1 // List<MultiKey> localDropdownKeysAndLabels = new ArrayList<MultiKey>(); // localDropdownKeysAndLabels.add(new MultiKey("", "")); // localDropdownKeysAndLabels.add(new MultiKey("key1", "value1")); // localDropdownKeysAndLabels.add(new MultiKey("key2", "value2")); // dropDownConfigAndValue.getGshTemplateInputConfig().setDropdownKeysAndLabels(localDropdownKeysAndLabels); // // GshTemplateInputConfigAndValue dropDownConfigAndValue2 = gshTemplateDecorateForUiInput.getGshTemplateInputConfigAndValues().get("gsh_input_dropDown2"); // // // if drop down 1 has somethign set // if (!StringUtils.isBlank(dropDownConfigAndValue.getValueOrDefault())) { // // // if the first option is selected, set the drop down 2 options to one set // if (StringUtils.equals("key1", dropDownConfigAndValue.getValueOrDefault())) { // List<MultiKey> localDropdownKeysAndLabels2 = new ArrayList<MultiKey>(); // localDropdownKeysAndLabels2.add(new MultiKey("", "")); // localDropdownKeysAndLabels2.add(new MultiKey("key1a", "value1a")); // localDropdownKeysAndLabels2.add(new MultiKey("key1b", "value1b")); // dropDownConfigAndValue2.getGshTemplateInputConfig().setDropdownKeysAndLabels(localDropdownKeysAndLabels2); // // // if the second option is selected, set the drop down 2 options to another set // } else if (StringUtils.equals("key2", dropDownConfigAndValue.getValueOrDefault())) { // List<MultiKey> localDropdownKeysAndLabels2 = new ArrayList<MultiKey>(); // localDropdownKeysAndLabels2.add(new MultiKey("", "")); // localDropdownKeysAndLabels2.add(new MultiKey("key2a", "value2a")); // localDropdownKeysAndLabels2.add(new MultiKey("key2b", "value2b")); // dropDownConfigAndValue2.getGshTemplateInputConfig().setDropdownKeysAndLabels(localDropdownKeysAndLabels2); // // } // // } // // // if drop down 1 is blank, hide the textfield (it is shown by default) // if (StringUtils.isBlank(dropDownConfigAndValue.getValue())) { // // gshTemplateDecorateForUiInput.getGshTemplateInputConfigAndValues().remove("gsh_input_textField"); // // // if drop down 1 was changed, then set the text field to its value (overwrite whats there) // } else if (StringUtils.equals("gsh_input_dropDown", gshTemplateDecorateForUiInput.getEventConfigId())) { // // GshTemplateInputConfigAndValue textFieldConfigAndValue = gshTemplateDecorateForUiInput.getGshTemplateInputConfigAndValues().get("gsh_input_textField"); // // // if the first option for drop down 1 is there, then set to one thing // if (StringUtils.equals("key1", dropDownConfigAndValue.getValue())) { // textFieldConfigAndValue.setValue("<key1 value default>"); // // // if the second option for drop down 1 is there, then set to another thing // } else if (StringUtils.equals("key2", dropDownConfigAndValue.getValue())) { // textFieldConfigAndValue.setValue("<key2 value default>"); // } // // // if drop down 1 is blank, leave the textfield unchanged } private static boolean isInGroup(TheState theState, String groupNameOrBucketName, String pennId, Long millis) { String groupName = groupNameOrBucketName; if (theState.bucketLabelToGroupName.containsKey(groupNameOrBucketName)) { groupName = theState.bucketLabelToGroupName.get(groupNameOrBucketName); } Map<String, List<Object[]>> pennIdToPointInTime = theState.groupNameToPennIdToPointInTime.get(groupName); if (pennIdToPointInTime == null) { return false; } List<Object[]> startMillisEndMillises = pennIdToPointInTime.get(pennId); if (startMillisEndMillises == null) { return false; } for (Object[] startMillisEndMillis : startMillisEndMillises) { Long startMillis = (Long)startMillisEndMillis[0]; Long endMillis = (Long)startMillisEndMillis[1]; if (startMillis != null && startMillis < millis && endMillis == null) { return true; } if (startMillis != null && startMillis < millis && endMillis != null && endMillis > millis) { return true; } } return false; } }
Shibboleth config
Resolver
<AttributeDefinition id="coarseAuthz" xsi:type="ScriptedAttribute"> <InputDataConnector ref="userDB" attributeNames="eduPersonEntitlement"/> <InputDataConnector ref="ldap-apps" attributeNames="cn appPolicy" /> <Script> <![CDATA[ logger = Java.type("org.slf4j.LoggerFactory").getLogger("resolver/coarseAuthz") coarseMapping = {'policy1':'grouper:path:one','policy2':'grouper:path:two','policy3':'grouper:path:three'} appPolicy = '' if (typeof appPolicy != "undefined" && appPolicy.getValues().size() > 0) { appPolicyValue = appPolicy.getValues().get(0) if (typeof eduPersonEntitlement !== 'undefined' && eduPersonEntitlement !== null && !eduPersonEntitlement.getValues().empty) { if (!eduPersonEntitlement.getValues().contains(coarseMapping[appPolicyValue])) { coarseAuthz.addValue("unauthorized") } } else { coarseAuthz.addValue("unauthorized") } } ]]> </Script> </AttributeDefinition>
Relied on a DataConnector for LDAP, and a standard ContextCheck Intercept
Intercept condition check
<bean id="shibboleth.coarse-authz.Condition" parent="shibboleth.Conditions.NOT"> <constructor-arg> <list> <bean class="net.shibboleth.idp.profile.logic.SimpleAttributePredicate" p:useUnfilteredAttributes="true"> <property name="attributeValueMap"> <map> <entry key="coarseAuthz"> <list> <value>unauthorized</value> </list> </entry> </map> </property> </bean> </list> </constructor-arg> </bean>
velocity template for relying party
#set ($rpContext = $profileRequestContext.getSubcontext('net.shibboleth.profile.context.RelyingPartyContext')) #set ($spEntityId = $rpContext.getRelyingPartyId()) #set ($spEntityId = $encoder.encodeForHTMLAttribute($spEntityId))
intercept velocity view
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <title>$title - $titleSuffix</title> <meta http-equiv="refresh" content="0;url=#springMessage("coarse-authz.url")$spEntityId"> </head> </html>
- No labels