Skip to content

Commit

Permalink
Schema update for new lockout activation properties and capability. R…
Browse files Browse the repository at this point in the history
…udimentary (untested) implementation in provisioning. Removing deprecated enableDisable capability.
  • Loading branch information
semancik committed Jul 10, 2014
1 parent 7931dfc commit b48915b
Show file tree
Hide file tree
Showing 8 changed files with 205 additions and 121 deletions.
65 changes: 65 additions & 0 deletions infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd
Expand Up @@ -2784,6 +2784,37 @@
</xsd:annotation>
</xsd:element>

<xsd:element name="lockoutStatus" type="tns:LockoutStatusType" minOccurs="0">
<xsd:annotation>
<xsd:documentation>
This defines the state of user or account lock-out. Lock-out means that the account
was temporarily disabled due to failed login attempts or a similar abuse attempt.

This value is usualy set by the resource (or midpoint internal authentication code).
It is unlikely that it can be set to the "locked" value. However it usually can be used
to unlock the account by setting this property to "normal" value.
</xsd:documentation>
<xsd:appinfo>
<a:displayName>Lock-out Status</a:displayName>
</xsd:appinfo>
</xsd:annotation>
</xsd:element>

<xsd:element name="lockoutExpirationTimestamp" type="xsd:dateTime" minOccurs="0">
<xsd:annotation>
<xsd:documentation>
Timestamp of a moment when account lockout expires and the account will
be normally usable again.

This is only an informational value. It should be considered as read-only
for most cases. It only makes sense if the lockoutStatus is not in the "normal" state.
</xsd:documentation>
<xsd:appinfo>
<a:displayName>Lock-out Expiration</a:displayName>
</xsd:appinfo>
</xsd:annotation>
</xsd:element>

</xsd:sequence>
<xsd:attribute name="id" type="xsd:long" use="optional"/>
</xsd:complexType>
Expand Down Expand Up @@ -2897,6 +2928,40 @@
</xsd:enumeration>
</xsd:restriction>
</xsd:simpleType>

<xsd:simpleType name="LockoutStatusType">
<xsd:annotation>
<xsd:documentation>
This defines the state of account lock-out. Lock-out means that the account
was temporarily disabled due to failed login attempts or a similar abuse attempt.
</xsd:documentation>
<xsd:appinfo>
<jaxb:typesafeEnumClass/>
</xsd:appinfo>
</xsd:annotation>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="normal">
<xsd:annotation>
<xsd:documentation>
Account is in normal (unlocked state). It is usable without limitations.
</xsd:documentation>
<xsd:appinfo>
<jaxb:typesafeEnumMember name="NORMAL"/>
</xsd:appinfo>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="locked">
<xsd:annotation>
<xsd:documentation>
The account has been locked. Log-in to the account is temporarily disabled.
</xsd:documentation>
<xsd:appinfo>
<jaxb:typesafeEnumMember name="LOCKED"/>
</xsd:appinfo>
</xsd:annotation>
</xsd:enumeration>
</xsd:restriction>
</xsd:simpleType>

<xsd:complexType name="ResourceType">
<xsd:annotation>
Expand Down
Expand Up @@ -91,22 +91,14 @@
<xsd:complexContent>
<xsd:extension base="tns:CapabilityType">
<xsd:sequence>
<xsd:element name="enableDisable" type="tns:ActivationStatusCapabilityType" minOccurs="0">
<xsd:annotation>
<xsd:documentation>
DEPRECATED. Does not work any more. Use "status" instead.
</xsd:documentation>
<xsd:appinfo>
<a:deprecated>true</a:deprecated>
</xsd:appinfo>
</xsd:annotation>
</xsd:element>
<xsd:element name="status" type="tns:ActivationStatusCapabilityType" minOccurs="0">
</xsd:element>
<xsd:element name="validFrom" type="tns:ActivationValidityCapabilityType" minOccurs="0">
</xsd:element>
<xsd:element name="validTo" type="tns:ActivationValidityCapabilityType" minOccurs="0">
</xsd:element>
<xsd:element name="lockoutStatus" type="tns:ActivationLockoutStatusCapabilityType" minOccurs="0">
</xsd:element>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
Expand All @@ -130,7 +122,6 @@
<xsd:documentation>
Name of the attribute to use for account enable/disable.
This is a configuration of simulated enable/disable capability.
UNSTABLE. This element may change in the future.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
Expand All @@ -139,7 +130,6 @@
<xsd:documentation>
Value to set to the attribute when the account should be enabled.
This is a configuration of simulated enable/disable capability.
UNSTABLE. This element may change in the future.

More than one value can be specified. All specified values will
be compared to the attribute when the activation status is read
Expand All @@ -155,7 +145,6 @@
<xsd:documentation>
Value to set to the attribute when the account should be disabled.
This is a configuration of simulated enable/disable capability.
UNSTABLE. This element may change in the future.

More than one value can be specified. All specified values will
be compared to the attribute when the activation status is read
Expand Down Expand Up @@ -199,6 +188,73 @@
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>

<xsd:complexType name="ActivationLockoutStatusCapabilityType">
<xsd:annotation>
<xsd:documentation>
Describes capability to provide lockout status (e.g. account temporarily disabled due to many failed login attempts).
</xsd:documentation>
</xsd:annotation>
<xsd:complexContent>
<xsd:extension base="tns:CapabilityType">
<xsd:sequence>
<xsd:element name="returnedByDefault" type="xsd:boolean" minOccurs="0" default="true"/>
<xsd:element name="attribute" type="xsd:QName" minOccurs="0">
<xsd:annotation>
<xsd:documentation>
Name of the attribute to use for account lockout status.
This is a configuration of simulated lockout capability.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="normalValue" type="xsd:string" minOccurs="0" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation>
Value to set to the attribute when the account is in a normal state (not locked out).
This is a configuration of simulated lockout capability.

More than one value can be specified. All specified values will
be compared to the attribute when the activation status is read
from the resource (get operation). The value that matches will determine
the activation state. But only the first value will be used when
storing the lockout state to the resource (add or modify operations).
All other values will be ignored.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="lockedValue" type="xsd:string" minOccurs="0" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation>
Value to set to the attribute when the account is locked out.
This is a configuration of simulated lockout capability.

More than one value can be specified. All specified values will
be compared to the attribute when the activation status is read
from the resource (get operation). The value that matches will determine
the lockout state. But only the first value will be used when
storing the activation state to the resource (add or modify operations).
All other values will be ignored.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="ignoreAttribute" type="xsd:boolean" minOccurs="0" default="true">
<xsd:annotation>
<xsd:documentation>
Flag that controls whether the original attribute should be ignored.

If set to true (or not present at all) the original attribute used as a source of
simulated capability is marked as "ignored" in the schema. If set to false then
the original attribute is still present in its original form in the schema.

This option is meaningful only for simulated enable/disable, i.e. in case that the
"attribute" element above is set.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>

<xsd:complexType name="CredentialsCapabilityType">
<xsd:annotation>
Expand Down
Expand Up @@ -90,7 +90,7 @@ public static void assertFocusDefinition(ComplexTypeDefinition complexTypeDefini
PrismContainerDefinition activationContainer = complexTypeDefinition.findContainerDefinition(UserType.F_ACTIVATION);
PrismAsserts.assertDefinition(activationContainer, UserType.F_ACTIVATION, ActivationType.COMPLEX_TYPE, 0, 1);
assertFalse("Activation is runtime", activationContainer.isRuntimeSchema());
assertEquals("Activation size", 10, activationContainer.getDefinitions().size());
assertEquals("Activation size", 12, activationContainer.getDefinitions().size());
PrismAsserts.assertPropertyDefinition(activationContainer, ActivationType.F_ADMINISTRATIVE_STATUS, SchemaConstants.C_ACTIVATION_STATUS_TYPE, 0, 1);

PrismContainerDefinition assignmentContainer = complexTypeDefinition.findContainerDefinition(UserType.F_ASSIGNMENT);
Expand Down
Expand Up @@ -1065,24 +1065,43 @@ private ActivationType completeActivation(PrismObject<ShadowType> shadow, Resour
if (ResourceTypeUtil.hasResourceNativeActivationCapability(resource)) {
return shadow.asObjectable().getActivation();
} else if (ResourceTypeUtil.hasActivationCapability(resource)) {
return convertFromSimulatedActivationAttributes(shadow, resource, parentResult);
return convertFromSimulatedActivationAttributes(resource, shadow, parentResult);
} else {
// No activation capability, nothing to do
return null;
}
}

private ActivationType convertFromSimulatedActivationAttributes(
PrismObject<ShadowType> shadow, ResourceType resource, OperationResult parentResult) {
private static ActivationType convertFromSimulatedActivationAttributes(ResourceType resource,
PrismObject<ShadowType> shadow, OperationResult parentResult) {
// LOGGER.trace("Start converting activation type from simulated activation atribute");
ActivationCapabilityType activationCapability = ResourceTypeUtil.getEffectiveCapability(resource,
ActivationCapabilityType.class);
if (activationCapability == null) {
return null;
}
ResourceAttributeContainer attributesContainer = ShadowUtil.getAttributesContainer(shadow);

ActivationType activationType = new ActivationType();

converFromSimulatedActivationAdministrativeStatus(activationType, activationCapability, resource, shadow, parentResult);

return activationType;
}

private static ActivationStatusCapabilityType getStatusCapability(ResourceType resource, ActivationCapabilityType activationCapability) {
ActivationStatusCapabilityType statusCapabilityType = activationCapability.getStatus();
if (statusCapabilityType != null) {
return statusCapabilityType;
}
return null;
}

private static void converFromSimulatedActivationAdministrativeStatus(ActivationType activationType, ActivationCapabilityType activationCapability,
ResourceType resource, PrismObject<ShadowType> shadow, OperationResult parentResult) {

ActivationStatusCapabilityType statusCapabilityType = getStatusCapability(resource, activationCapability);

ResourceAttributeContainer attributesContainer = ShadowUtil.getAttributesContainer(shadow);
ResourceAttribute<?> activationProperty = null;
if (statusCapabilityType != null && statusCapabilityType.getAttribute() != null) {
activationProperty = attributesContainer.findAttribute(statusCapabilityType.getAttribute());
Expand All @@ -1094,19 +1113,19 @@ private ActivationType convertFromSimulatedActivationAttributes(
// return null;
// }

Collection<Object> values = null;

Collection<Object> activationValues = null;
if (activationProperty != null) {
values = activationProperty.getRealValues(Object.class);
activationValues = activationProperty.getRealValues(Object.class);
}
ActivationType activation = convertFromSimulatedActivationValues(resource, values, parentResult);

converFromSimulatedActivationAdministrativeStatusInternal(activationType, statusCapabilityType, resource, activationValues, parentResult);

LOGGER.trace(
"Detected simulated activation attribute {} on {} with value {}, resolved into {}",
new Object[] { SchemaDebugUtil.prettyPrint(statusCapabilityType.getAttribute()),
ObjectTypeUtil.toShortString(resource), values,
activation == null ? "null" : activation.getAdministrativeStatus() });
ObjectTypeUtil.toShortString(resource), activationValues,
activationType == null ? "null" : activationType.getAdministrativeStatus() });

// TODO: make this optional
// Remove the attribute which is the source of simulated activation. If we leave it there then we
// will have two ways to set activation.
if (statusCapabilityType.isIgnoreAttribute() == null
Expand All @@ -1115,70 +1134,27 @@ private ActivationType convertFromSimulatedActivationAttributes(
attributesContainer.remove(activationProperty);
}
}

return activation;

}

private static ActivationType convertFromSimulatedActivationAttributes(ResourceType resource,
ShadowType shadow, OperationResult parentResult) {
// LOGGER.trace("Start converting activation type from simulated activation atribute");
ActivationCapabilityType activationCapability = ResourceTypeUtil.getEffectiveCapability(resource,
ActivationCapabilityType.class);

ActivationStatusCapabilityType statusCapabilityType = getStatusCapability(resource, activationCapability);
/**
* Moved to a separate method especially to enable good logging (see above).
*/
private static void converFromSimulatedActivationAdministrativeStatusInternal(ActivationType activationType, ActivationStatusCapabilityType statusCapabilityType,
ResourceType resource, Collection<Object> activationValues, OperationResult parentResult) {

QName enableDisableAttribute = statusCapabilityType.getAttribute();
List<Object> values = ShadowUtil.getAttributeValues(shadow, enableDisableAttribute);
ActivationType activation = convertFromSimulatedActivationValues(resource, values, parentResult);
LOGGER.trace(
"Detected simulated activation attribute {} on {} with value {}, resolved into {}",
new Object[] { SchemaDebugUtil.prettyPrint(statusCapabilityType.getAttribute()),
ObjectTypeUtil.toShortString(resource), values,
activation == null ? "null" : activation.getAdministrativeStatus() });
return activation;
}

private static ActivationStatusCapabilityType getStatusCapability(ResourceType resource, ActivationCapabilityType activationCapability) {
ActivationStatusCapabilityType statusCapabilityType = activationCapability.getStatus();
if (statusCapabilityType != null) {
if (activationCapability.getEnableDisable() != null) {
LOGGER.warn("There is deprecated enableDisable activation capability in "+resource+", ignoring it");
}
return statusCapabilityType;
}
if (activationCapability.getEnableDisable() != null) {
LOGGER.warn("There is deprecated enableDisable activation capability in "+resource+"; using it instead of status capability");
return activationCapability.getEnableDisable();
}
return null;
}

private static ActivationType convertFromSimulatedActivationValues(ResourceType resource,
Collection<Object> activationValues, OperationResult parentResult) {

ActivationCapabilityType activationCapability = ResourceTypeUtil.getEffectiveCapability(resource,
ActivationCapabilityType.class);
if (activationCapability == null) {
return null;
}

ActivationStatusCapabilityType statusCapabilityType = getStatusCapability(resource, activationCapability);
List<String> disableValues = statusCapabilityType.getDisableValue();
List<String> enableValues = statusCapabilityType.getEnableValue();

ActivationType activationType = new ActivationType();
List<String> enableValues = statusCapabilityType.getEnableValue();

if (MiscUtil.isNoValue(activationValues)) {

if (MiscUtil.hasNoValue(disableValues)) {
activationType.setAdministrativeStatus(ActivationStatusType.DISABLED);
return activationType;
return;
}

if (MiscUtil.hasNoValue(enableValues)) {
activationType.setAdministrativeStatus(ActivationStatusType.ENABLED);
return activationType;
return;
}

// No activation information.
Expand All @@ -1189,7 +1165,7 @@ private static ActivationType convertFromSimulatedActivationValues(ResourceType
+ " has native activation capability but noes not provide value for DISABLE attribute");
}

return null;
return;

} else {
if (activationValues.size() > 1) {
Expand All @@ -1205,21 +1181,20 @@ private static ActivationType convertFromSimulatedActivationValues(ResourceType
for (String disable : disableValues) {
if (disable.equals(String.valueOf(disableObj))) {
activationType.setAdministrativeStatus(ActivationStatusType.DISABLED);
return activationType;
return;
}
}

for (String enable : enableValues) {
if ("".equals(enable) || enable.equals(String.valueOf(disableObj))) {
activationType.setAdministrativeStatus(ActivationStatusType.ENABLED);
return activationType;
return;
}
}
}

return null;
}

private ActivationStatusCapabilityType getActivationStatusFromSimulatedActivation(ShadowType shadow, ResourceType resource, OperationResult result){
ActivationCapabilityType activationCapability = ResourceTypeUtil.getEffectiveCapability(resource,
ActivationCapabilityType.class);
Expand Down

0 comments on commit b48915b

Please sign in to comment.