Skip to content

Commit 4b96824

Browse files
Merge pull request #3993 from Kuliak/add-eligibilities-attr
feat(core): virtual attribute for eligibilities
2 parents 42d3641 + 76bd8c7 commit 4b96824

File tree

7 files changed

+279
-2
lines changed

7 files changed

+279
-2
lines changed

perun-core/src/main/java/cz/metacentrum/perun/core/blImpl/AttributesManagerBlImpl.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7985,6 +7985,17 @@ protected void initialize() {
79857985
policies.add(Triple.of(Role.GROUPADMIN, READ, RoleObject.None));
79867986
attributes.put(attr, createInitialPolicyCollections(policies));
79877987

7988+
//urn:perun:user:attribute-def:virt:userEligibilities
7989+
attr = new AttributeDefinition();
7990+
attr.setNamespace(AttributesManager.NS_USER_ATTR_VIRT);
7991+
attr.setFriendlyName("userEligibilities");
7992+
attr.setDisplayName("user Eligibilities");
7993+
attr.setType(LinkedHashMap.class.getName());
7994+
attr.setDescription("Virtual attribute, which collects all eligibilities user ext source attributes " +
7995+
"with keys and values (map). Only the highest value is selected for each key.");
7996+
policies = new ArrayList<>();
7997+
attributes.put(attr, createInitialPolicyCollections(policies));
7998+
79887999
//urn:perun:group:attribute-def:virt:autoRegistrationEnabled
79898000
attr = new AttributeDefinition();
79908001
attr.setNamespace(AttributesManager.NS_GROUP_ATTR_VIRT);
@@ -8079,6 +8090,17 @@ protected void initialize() {
80798090
policies.add(Triple.of(Role.PROXY, WRITE, RoleObject.None));
80808091
attributes.put(attr, createInitialPolicyCollections(policies));
80818092

8093+
//urn_perun_ues_attribute_def_def_eligibilities
8094+
attr = new AttributeDefinition();
8095+
attr.setNamespace(AttributesManager.NS_UES_ATTR_DEF);
8096+
attr.setType(LinkedHashMap.class.getName());
8097+
attr.setFriendlyName("eligibilities");
8098+
attr.setDisplayName("eligibilities");
8099+
attr.setDescription("eligibilities");
8100+
8101+
policies = new ArrayList<>();
8102+
attributes.put(attr, createInitialPolicyCollections(policies));
8103+
80828104
//urn_perun_ues_attribute_def_def_IdPOrganizationName
80838105
attr = new AttributeDefinition();
80848106
attr.setNamespace(AttributesManager.NS_UES_ATTR_DEF);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
package cz.metacentrum.perun.core.impl.modules.attributes;
2+
3+
import cz.metacentrum.perun.core.api.Attribute;
4+
import cz.metacentrum.perun.core.api.AttributeDefinition;
5+
import cz.metacentrum.perun.core.api.AttributesManager;
6+
import cz.metacentrum.perun.core.api.User;
7+
import cz.metacentrum.perun.core.api.UserExtSource;
8+
import cz.metacentrum.perun.core.api.exceptions.AttributeNotExistsException;
9+
import cz.metacentrum.perun.core.api.exceptions.WrongAttributeAssignmentException;
10+
import cz.metacentrum.perun.core.impl.PerunSessionImpl;
11+
import cz.metacentrum.perun.core.implApi.modules.attributes.SkipValueCheckDuringDependencyCheck;
12+
import cz.metacentrum.perun.core.implApi.modules.attributes.UserVirtualAttributeCollectedFromUserExtSource;
13+
14+
import java.util.LinkedHashMap;
15+
import java.util.List;
16+
import java.util.Map;
17+
18+
/**
19+
* Virtual attribute for user's eligibilities.
20+
* Attribute is calculated using all user's ext sources and their corresponding eligibilities
21+
* attribute so that for each unique key (name) only the highest obtained value is selected.
22+
*
23+
* @author Luboslav Halama
24+
*/
25+
@SuppressWarnings("unused")
26+
@SkipValueCheckDuringDependencyCheck
27+
public class urn_perun_user_attribute_def_virt_userEligibilities extends UserVirtualAttributeCollectedFromUserExtSource {
28+
29+
private final static String USER_ELIGIBILITIES_FRIENDLY_NAME = "userEligibilities";
30+
private final static String A_U_V_USER_ELIGIBILITIES = AttributesManager.NS_USER_ATTR_VIRT + ":" + USER_ELIGIBILITIES_FRIENDLY_NAME;
31+
32+
@Override
33+
public String getSourceAttributeFriendlyName() {
34+
return "eligibilities";
35+
}
36+
37+
@Override
38+
public String getDestinationAttributeFriendlyName() {
39+
return USER_ELIGIBILITIES_FRIENDLY_NAME;
40+
}
41+
42+
@Override
43+
public Attribute getAttributeValue(PerunSessionImpl sess, User user, AttributeDefinition attributeDefinition) {
44+
List<UserExtSource> userExtSources = sess.getPerunBl().getUsersManagerBl().getUserExtSources(sess, user);
45+
46+
Map<String, String> collectedEligibilities = new LinkedHashMap<>();
47+
48+
for (UserExtSource extSource : userExtSources) {
49+
Attribute attribute;
50+
try {
51+
attribute = sess.getPerunBl().getAttributesManagerBl().getAttribute(sess, extSource,
52+
AttributesManager.NS_UES_ATTR_DEF + ":" + getSourceAttributeFriendlyName());
53+
} catch (AttributeNotExistsException | WrongAttributeAssignmentException e) {
54+
throw new RuntimeException(e);
55+
}
56+
57+
Map<String, String> eligibilities = attribute.valueAsMap();
58+
59+
// if no eligibilities were obtained, skip this ext source
60+
if (eligibilities == null) {
61+
continue;
62+
}
63+
64+
for (String key : eligibilities.keySet()) {
65+
66+
// if given key is not present yet, store it
67+
if (!collectedEligibilities.containsKey(key)) {
68+
collectedEligibilities.put(key, eligibilities.get(key));
69+
continue;
70+
}
71+
72+
// if given is present, check if value should be updated
73+
int timestamp = Integer.parseInt(eligibilities.get(key));
74+
if (Integer.parseInt(collectedEligibilities.get(key)) < timestamp) {
75+
collectedEligibilities.replace(key, eligibilities.get(key));
76+
}
77+
}
78+
}
79+
80+
Attribute attribute = new Attribute(attributeDefinition);
81+
attribute.setValue(collectedEligibilities);
82+
return attribute;
83+
}
84+
85+
// @Override
86+
// public List<AttributeHandleIdentifier> getHandleIdentifiers() {
87+
// List<AttributeHandleIdentifier> handleIdentifiers = super.getHandleIdentifiers();
88+
// handleIdentifiers.add(auditEvent -> {
89+
// if (auditEvent instanceof AttributeChangedForUser &&
90+
// ((AttributeChangedForUser) auditEvent).getAttribute().getFriendlyName().equals(getDestinationAttributeFriendlyName())) {
91+
// return ((AttributeChangedForUser) auditEvent).getUser().getId();
92+
// } else {
93+
// return null;
94+
// }
95+
// });
96+
// return handleIdentifiers;
97+
// }
98+
//
99+
// @Override
100+
// public List<AuditEvent> resolveVirtualAttributeValueChange(PerunSessionImpl perunSession, AuditEvent message) throws AttributeNotExistsException, WrongAttributeAssignmentException, WrongReferenceAttributeValueException {
101+
// List<AuditEvent> resolvingMessages = super.resolveVirtualAttributeValueChange(perunSession, message);
102+
// if (message == null) return resolvingMessages;
103+
//
104+
// if (message instanceof AttributeSetForUser &&
105+
// ((AttributeSetForUser) message).getAttribute().getFriendlyName().equals(getSecondarySourceAttributeFriendlyName())) {
106+
// AttributeDefinition attrVirtUserEligibilitiesDefinition = perunSession.getPerunBl().getAttributesManagerBl().getAttributeDefinition(perunSession, A_U_V_USER_ELIGIBILITIES);
107+
// resolvingMessages.add(new AttributeSetForUser(new Attribute(attrVirtUserEligibilitiesDefinition), ((AttributeSetForUser) message).getUser()));
108+
// } else if (message instanceof AttributeChangedForUser) {
109+
// AttributeDefinition attrVirtUserEligibilitiesDefinition = perunSession.getPerunBl().getAttributesManagerBl().getAttributeDefinition(perunSession, A_U_V_USER_ELIGIBILITIES);
110+
// resolvingMessages.add(new AttributeChangedForUser(new Attribute(attrVirtUserEligibilitiesDefinition), ((AttributeChangedForUser) message).getUser()));
111+
// } else if (message instanceof AttributeRemovedForUser) {
112+
// AttributeDefinition attrVirtUserEligibilitiesDefinition = perunSession.getPerunBl().getAttributesManagerBl().getAttributeDefinition(perunSession, A_U_V_USER_ELIGIBILITIES);
113+
// resolvingMessages.add(new AttributeRemovedForUser(new Attribute(attrVirtUserEligibilitiesDefinition), ((AttributeRemovedForUser) message).getUser()));
114+
// }
115+
//
116+
// return resolvingMessages;
117+
// }
118+
119+
// private AuditEvent resolveEvent(PerunSessionImpl perunSession, User user) throws AttributeNotExistsException {
120+
// AttributeDefinition attrVirtUserEligibilitiesDefinition = perunSession.getPerunBl().getAttributesManagerBl().getAttributeDefinition(perunSession, A_U_V_USER_ELIGIBILITIES);
121+
// return new AttributeChangedForUser(new Attribute(attrVirtUserEligibilitiesDefinition), user);
122+
// }
123+
124+
@Override
125+
public AttributeDefinition getAttributeDefinition() {
126+
AttributeDefinition attr = new AttributeDefinition();
127+
attr.setNamespace(AttributesManager.NS_USER_ATTR_VIRT);
128+
attr.setFriendlyName(USER_ELIGIBILITIES_FRIENDLY_NAME);
129+
attr.setDisplayName("user eligibilities");
130+
attr.setType(LinkedHashMap.class.getName());
131+
attr.setDescription("Virtual attribute, which collects all eligibilities user ext source attributes " +
132+
"with keys and values (map). Only the highest value is selected for each key.");
133+
return attr;
134+
}
135+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
package cz.metacentrum.perun.core.impl.modules.attributes;
2+
3+
import cz.metacentrum.perun.core.api.Attribute;
4+
import cz.metacentrum.perun.core.api.AttributeDefinition;
5+
import cz.metacentrum.perun.core.api.AttributesManager;
6+
import cz.metacentrum.perun.core.api.ExtSource;
7+
import cz.metacentrum.perun.core.api.ExtSourcesManager;
8+
import cz.metacentrum.perun.core.api.User;
9+
import cz.metacentrum.perun.core.api.UserExtSource;
10+
import cz.metacentrum.perun.core.bl.AttributesManagerBl;
11+
import cz.metacentrum.perun.core.bl.PerunBl;
12+
import cz.metacentrum.perun.core.bl.UsersManagerBl;
13+
import cz.metacentrum.perun.core.impl.PerunSessionImpl;
14+
import org.junit.Before;
15+
import org.junit.Test;
16+
17+
import java.util.HashMap;
18+
import java.util.LinkedHashMap;
19+
import java.util.List;
20+
import java.util.Map;
21+
22+
import static org.junit.Assert.assertEquals;
23+
import static org.junit.Assert.assertTrue;
24+
import static org.mockito.Mockito.mock;
25+
import static org.mockito.Mockito.when;
26+
27+
public class urn_perun_user_attribute_def_virt_userEligibilitiesTest {
28+
29+
private static urn_perun_user_attribute_def_virt_userEligibilities classInstance;
30+
private static PerunSessionImpl session;
31+
private static User user;
32+
private static Attribute uesAttribute1;
33+
private static Attribute uesAttribute2;
34+
private static Attribute userEligibilitiesAttribute;
35+
private static AttributeDefinition userEligibilitiesAttributeDefinition;
36+
37+
@Before
38+
public void setUp() throws Exception {
39+
classInstance = new urn_perun_user_attribute_def_virt_userEligibilities();
40+
session = mock(PerunSessionImpl.class);
41+
user = new User();
42+
UserExtSource extSource = new UserExtSource(new ExtSource("test ext source", ExtSourcesManager.EXTSOURCE_LDAP), "test-login");
43+
UserExtSource extSource2 = new UserExtSource(new ExtSource("another test ext source", ExtSourcesManager.EXTSOURCE_LDAP), "test-login2");
44+
45+
userEligibilitiesAttributeDefinition = new AttributeDefinition();
46+
userEligibilitiesAttributeDefinition.setNamespace(AttributesManager.NS_USER_ATTR_VIRT);
47+
userEligibilitiesAttributeDefinition.setFriendlyName("userEligibilities");
48+
userEligibilitiesAttributeDefinition.setDisplayName("user eligibilities");
49+
userEligibilitiesAttributeDefinition.setType(HashMap.class.getName());
50+
userEligibilitiesAttributeDefinition.setDescription("Virtual attribute, which collects all eligibilities user ext source attributes " +
51+
"with keys and values (map). Only the highest value is selected for each key.");
52+
userEligibilitiesAttribute = new Attribute(userEligibilitiesAttributeDefinition);
53+
54+
AttributeDefinition attrDef = new AttributeDefinition();
55+
attrDef.setFriendlyName("eligibilities");
56+
attrDef.setType(AttributesManager.NS_UES_ATTR_DEF);
57+
attrDef.setDescription("eligibilities test attribute");
58+
uesAttribute1 = new Attribute(attrDef);
59+
uesAttribute2 = new Attribute(attrDef);
60+
61+
Map<String, String> attrValue = new LinkedHashMap<>();
62+
attrValue.put("cesnet", "8150000");
63+
uesAttribute1.setValue(attrValue);
64+
65+
attrValue = new LinkedHashMap<>();
66+
attrValue.put("cesnet", "9999999");
67+
attrValue.put("mu", "1000000");
68+
uesAttribute2.setValue(attrValue);
69+
70+
when(session.getPerunBl()).thenReturn(mock(PerunBl.class));
71+
when(session.getPerunBl().getUsersManagerBl()).thenReturn(mock(UsersManagerBl.class));
72+
when(session.getPerunBl().getAttributesManagerBl()).thenReturn(mock(AttributesManagerBl.class));
73+
74+
when(session.getPerunBl().getUsersManagerBl().getUserExtSources(session, user)).thenReturn(List.of(extSource, extSource2));
75+
when(session.getPerunBl().getAttributesManagerBl().getAttribute(session, user, AttributesManager.NS_USER_ATTR_VIRT + ":userEligibilities"))
76+
.thenReturn(userEligibilitiesAttribute);
77+
when(session.getPerunBl().getAttributesManagerBl().getAttribute(session, extSource, AttributesManager.NS_UES_ATTR_DEF + ":eligibilities"))
78+
.thenReturn(uesAttribute1);
79+
when(session.getPerunBl().getAttributesManagerBl().getAttribute(session, extSource2, AttributesManager.NS_UES_ATTR_DEF + ":eligibilities"))
80+
.thenReturn(uesAttribute2);
81+
}
82+
83+
@Test
84+
public void getEligibilitiesAttributeValue() throws Exception {
85+
System.out.println("getEligibilitiesAttributeValue()");
86+
87+
Attribute attr = classInstance.getAttributeValue(session, user, userEligibilitiesAttributeDefinition);
88+
Map<String, String> values = (LinkedHashMap<String, String>) attr.getValue();
89+
90+
assertEquals(2, values.size());
91+
assertTrue(values.keySet().containsAll(List.of("cesnet", "mu")));
92+
93+
for (String key : values.keySet()) {
94+
String value = values.get(key);
95+
if (key.equals("cesnet")) {
96+
assertEquals("9999999", value);
97+
} else {
98+
assertEquals("1000000", value);
99+
}
100+
}
101+
}
102+
}

perun-db/addProxyRolePolicies

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ my @readAttributes = (
3131
"urn:perun:user:attribute-def:virt:voPersonExternalAffiliation",
3232
"urn:perun:user:attribute-def:virt:forwardedVoPersonExternalAffiliation",
3333
"urn:perun:user:attribute-def:virt:sponsoredMembershipInOrganizations",
34+
"urn:perun:user:attribute-def:virt:userEligibilities",
3435
"urn:perun:user:attribute-def:def:preferredMail",
3536
"urn:perun:user:attribute-def:def:timezone",
3637
"urn:perun:user:attribute-def:def:preferredLanguage",

perun-ldapc/src/main/java/cz/metacentrum/perun/ldapc/model/PerunAttribute.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import cz.metacentrum.perun.core.api.Attribute;
44
import cz.metacentrum.perun.core.api.AttributeDefinition;
55
import cz.metacentrum.perun.core.api.PerunBean;
6-
import cz.metacentrum.perun.core.api.exceptions.InternalErrorException;
76

87
public interface PerunAttribute<T extends PerunBean> {
98

@@ -25,6 +24,7 @@ public interface PerunAttributeNames {
2524
public static final String perunAttrClientID = "OIDCClientID";
2625
public static final String perunAttrGroupNames = "groupNames";
2726
public static final String perunAttrInstitutionsCountries = "institutionsCountries";
27+
public static final String perunAttrUserEligibilities = "userEligibilities";
2828

2929
//LDAP ATTRIBUTES NAMES
3030
public static final String ldapAttrAssignedToResourceId = "assignedToResourceId";
@@ -74,6 +74,7 @@ public interface PerunAttributeNames {
7474
public static final String ldapAttrAdminOfGroup = "adminOfGroup";
7575
public static final String ldapAttrAdminOfFacility = "adminOfFacility";
7676
public static final String ldapAttrUuid = "uuid";
77+
public static final String ldapAttrUserEligibilities = "userEligibilities";
7778

7879
//LDAP OBJECT CLASSES
7980
public static final String objectClassTop = "top";

perun-ldapc/src/main/resources/perun-ldapc.xml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,6 +1294,21 @@ http://www.springframework.org/schema/aop http://www.springframework.org/schema/
12941294
</bean>
12951295
</property>
12961296
</bean>
1297+
<bean class="cz.metacentrum.perun.ldapc.model.impl.PerunAttributeDesc">
1298+
<property name="name" value="userEligibilities"/>
1299+
<property name="required" value="false"/>
1300+
<property name="multipleValuesExtractor">
1301+
<bean class="cz.metacentrum.perun.ldapc.model.impl.MultipleAttributeValueExtractor">
1302+
<property name="name" value="userEligibilities"/>
1303+
<property name="namespace" value="urn:perun:user:attribute-def:virt"/>
1304+
<property name="valueTransformer" >
1305+
<bean class="cz.metacentrum.perun.ldapc.beans.MapEntryValueTransformer">
1306+
<property name="separator" value="=" />
1307+
</bean>
1308+
</property>
1309+
</bean>
1310+
</property>
1311+
</bean>
12971312
</list>
12981313
</property>
12991314
<property name="attributeDescriptionsExt" ref="perunUserAttributesExt"/>

perun-utils/ldapc-scripts/schemas/perun-schema.ldif

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,10 @@ olcAttributeTypes: {83}( 1.3.6.1.4.1.8057.2.80.89 NAME 'securityText' DESC 'Secu
8888
olcAttributeTypes: {84}( 1.3.6.1.4.1.8057.2.80.90 NAME 'earliestActiveLastAccess' DESC 'Timestamp of the earliest active IdP extSource lastAccess' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
8989
olcAttributeTypes: {85}( 1.3.6.1.4.1.25178.4.1.11 NAME 'voPersonExternalAffiliation' DESC 'voPerson Scoped External Affiliation' EQUALITY caseIgnoreMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' )
9090
olcAttributeTypes: {86}( 1.3.6.1.4.1.8057.2.80.91 NAME 'forwardedVoPersonExternalAffiliation' DESC 'forwardedVoPerson Scoped External Affiliation' EQUALITY caseExactMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' )
91+
olcAttributeTypes: {87}( 1.3.6.1.4.1.8057.2.80.92 NAME 'userEligibilities' DESC 'user ext source eligibilities attributes with only the highest value is selected for each key.' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
9192
-
9293
replace: olcObjectClasses
93-
olcObjectClasses: {0}( 1.3.6.1.4.1.8057.2.80.4 NAME 'perunUser' DESC 'User managed by Perun' SUP inetOrgPerson STRUCTURAL MUST ( perunUserId $ isServiceUser $ isSponsoredUser ) MAY ( preferredMail $ userCertificateSubject $ uidNumber $ login $ eduPersonPrincipalNames $ userPassword $ memberOfPerunVo $ libraryIDs $ schacHomeOrganizations $ eduPersonScopedAffiliations $ voPersonExternalAffiliation $ forwardedVoPersonExternalAffiliation $ bonaFideStatus $ groupNames $ institutionsCountries $ isCesnetEligible $ loa $ internalUserIdentifiers $ eduPersonOrcid $ loaFenix $ adminOfVo $ adminOfGroup $ adminOfFacility $ eduPersonEntitlement $ europeanStudentID $ eIDASPersonIdentifier $ timezone $ phone $ address $ aups $ tcsMails $ sshPublicKey $ sponsoredMembershipInOrganizations $ userIdentities $ schacPersonalUniqueCodes $ securityImage $ mfaEnforced $ mfaTokens $ uuid $ oouEinfraSignedV1 $ cscaleCompany $ cscaleUserCategory $ cscaleAcceptEmail $ cscaleResearchField $ cscaleUserFunction $ userAup $ cscaleCountry $ unscopedLogin $ mfaEnforceSettings $ securityText $ earliestActiveLastAccess) )
94+
olcObjectClasses: {0}( 1.3.6.1.4.1.8057.2.80.4 NAME 'perunUser' DESC 'User managed by Perun' SUP inetOrgPerson STRUCTURAL MUST ( perunUserId $ isServiceUser $ isSponsoredUser ) MAY ( preferredMail $ userCertificateSubject $ uidNumber $ login $ eduPersonPrincipalNames $ userPassword $ memberOfPerunVo $ libraryIDs $ schacHomeOrganizations $ eduPersonScopedAffiliations $ voPersonExternalAffiliation $ forwardedVoPersonExternalAffiliation $ bonaFideStatus $ groupNames $ institutionsCountries $ isCesnetEligible $ loa $ internalUserIdentifiers $ eduPersonOrcid $ loaFenix $ adminOfVo $ adminOfGroup $ adminOfFacility $ eduPersonEntitlement $ europeanStudentID $ eIDASPersonIdentifier $ timezone $ phone $ address $ aups $ tcsMails $ sshPublicKey $ sponsoredMembershipInOrganizations $ userIdentities $ schacPersonalUniqueCodes $ securityImage $ mfaEnforced $ mfaTokens $ uuid $ oouEinfraSignedV1 $ cscaleCompany $ cscaleUserCategory $ cscaleAcceptEmail $ cscaleResearchField $ cscaleUserFunction $ userAup $ cscaleCountry $ unscopedLogin $ mfaEnforceSettings $ securityText $ earliestActiveLastAccess $ userEligibilities) )
9495
olcObjectClasses: {1}( 1.3.6.1.4.1.8057.2.80.5 NAME 'perunGroup' DESC 'Group managed by Perun' SUP top STRUCTURAL MUST ( cn $ perunGroupId $ perunVoId $ perunUniqueGroupName ) MAY ( uniqueMember $ businessCategory $ seeAlso $ owner $ ou $ o $ description $ perunParentGroup $ perunParentGroupId $ assignedToResourceId $ adminOfVo $ adminOfGroup $ adminOfFacility $ groupAffiliations $ uuid ) )
9596
olcObjectClasses: {2}( 1.3.6.1.4.1.8057.2.80.15 NAME 'perunResource' DESC 'Resource managed by Perun' SUP top STRUCTURAL MUST ( cn $ perunResourceId $ perunVoId $ perunFacilityId ) MAY (uniqueMember $ businessCategory $ seeAlso $ owner $ ou $ o $ description $ assignedGroupId $ perunFacilityDn $ capabilities $ isAssignedWithSubgroups $ uuid ) )
9697
olcObjectClasses: {3}( 1.3.6.1.4.1.8057.2.80.6 NAME 'perunVO' DESC 'VO managed by Perun' SUP organization STRUCTURAL MUST perunVoId MAY ( uniqueMember $ aup ) )

0 commit comments

Comments
 (0)