[KEYCLOAK-6853] Make TimePolicyProvider use the kc.date.time_date contextual attribute when evaluating policies

This commit is contained in:
Stefan Guilhen 2018-04-04 14:37:03 -03:00
parent f652b13520
commit 87abe5e648
3 changed files with 72 additions and 6 deletions

View file

@ -21,8 +21,10 @@ import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import org.keycloak.authorization.attribute.Attributes;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.policy.evaluation.Evaluation;
import org.keycloak.authorization.policy.evaluation.EvaluationContext;
import org.keycloak.authorization.policy.provider.PolicyProvider;
/**
@ -30,15 +32,25 @@ import org.keycloak.authorization.policy.provider.PolicyProvider;
*/
public class TimePolicyProvider implements PolicyProvider {
static String DEFAULT_DATE_PATTERN = "yyyy-MM-dd hh:mm:ss";
static String DEFAULT_DATE_PATTERN = "yyyy-MM-dd HH:mm:ss";
static String CONTEXT_TIME_ENTRY = "kc.time.date_time";
@Override
public void evaluate(Evaluation evaluation) {
Policy policy = evaluation.getPolicy();
SimpleDateFormat dateFormat = new SimpleDateFormat(DEFAULT_DATE_PATTERN);
Date actualDate = new Date();
try {
String contextTime = null;
EvaluationContext context = evaluation.getContext();
if (context.getAttributes() != null && context.getAttributes().exists(CONTEXT_TIME_ENTRY)) {
Attributes.Entry contextTimeEntry = context.getAttributes().getValue(CONTEXT_TIME_ENTRY);
if (!contextTimeEntry.isEmpty()) {
contextTime = contextTimeEntry.asString(0);
}
}
Date actualDate = contextTime == null ? new Date() : dateFormat.parse(contextTime);
String notBefore = policy.getConfig().get("nbf");
if (notBefore != null && !"".equals(notBefore)) {
if (actualDate.before(dateFormat.parse(format(notBefore)))) {

View file

@ -53,7 +53,7 @@ public class DefaultEvaluationContext implements EvaluationContext {
public Map<String, Collection<String>> getBaseAttributes() {
HashMap<String, Collection<String>> attributes = new HashMap<>();
attributes.put("kc.time.date_time", Arrays.asList(new SimpleDateFormat("MM/dd/yyyy hh:mm:ss").format(new Date())));
attributes.put("kc.time.date_time", Arrays.asList(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())));
attributes.put("kc.client.network.ip_address", Arrays.asList(this.keycloakSession.getContext().getConnection().getRemoteAddr()));
attributes.put("kc.client.network.host", Arrays.asList(this.keycloakSession.getContext().getConnection().getRemoteHost()));

View file

@ -16,7 +16,10 @@
*/
package org.keycloak.testsuite.authz;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -54,6 +57,7 @@ import org.keycloak.representations.idm.GroupRepresentation;
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.authorization.JSPolicyRepresentation;
import org.keycloak.representations.idm.authorization.TimePolicyRepresentation;
import org.keycloak.testsuite.runonserver.RunOnServerDeployment;
import org.keycloak.testsuite.util.ClientBuilder;
import org.keycloak.testsuite.util.GroupBuilder;
@ -123,6 +127,39 @@ public class PolicyEvaluationTest extends AbstractAuthzTest {
return RunOnServerDeployment.create(AbstractAuthzTest.class);
}
@Test
public void testCheckDateAndTime() {testingClient.server().run(PolicyEvaluationTest::testCheckDateAndTime);}
public static void testCheckDateAndTime(KeycloakSession session) {
session.getContext().setRealm(session.realms().getRealmByName("authz-test"));
AuthorizationProvider authorization = session.getProvider(AuthorizationProvider.class);
ClientModel clientModel = session.realms().getClientByClientId("resource-server-test", session.getContext().getRealm());
StoreFactory storeFactory = authorization.getStoreFactory();
ResourceServer resourceServer = storeFactory.getResourceServerStore().findById(clientModel.getId());
TimePolicyRepresentation policyRepresentation = new TimePolicyRepresentation();
policyRepresentation.setName("testCheckDateAndTime");
// set the notOnOrAfter for 1 hour from now
long notOnOrAfter = System.currentTimeMillis() + 3600000;
Date notOnOrAfterDate = new Date(notOnOrAfter);
policyRepresentation.setNotOnOrAfter(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(notOnOrAfterDate));
// evaluation should succeed with the default context as it uses the current time as the date to be compared.
Policy policy = storeFactory.getPolicyStore().create(policyRepresentation, resourceServer);
PolicyProvider provider = authorization.getProvider(policy.getType());
DefaultEvaluation evaluation = createEvaluation(session, authorization, resourceServer, policy);
provider.evaluate(evaluation);
Assert.assertEquals(Effect.PERMIT, evaluation.getEffect());
// lets now override the context to use a time that exceeds the time that was set in the policy.
long contextTime = System.currentTimeMillis() + 5400000;
Map<String,Collection<String>> attributes = new HashMap<>();
attributes.put("kc.time.date_time", Arrays.asList(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(contextTime))));
evaluation = createEvaluation(session, authorization, null, resourceServer, policy, attributes);
provider.evaluate(evaluation);
Assert.assertEquals(Effect.DENY, evaluation.getEffect());
}
@Test
public void testCheckUserInGroup() {
testingClient.server().run(PolicyEvaluationTest::testCheckUserInGroup);
@ -599,6 +636,12 @@ public class PolicyEvaluationTest extends AbstractAuthzTest {
}
private static DefaultEvaluation createEvaluation(KeycloakSession session, AuthorizationProvider authorization, Resource resource, ResourceServer resourceServer, Policy policy) {
return createEvaluation(session, authorization, resource, resourceServer, policy, null);
}
private static DefaultEvaluation createEvaluation(KeycloakSession session, AuthorizationProvider authorization,
Resource resource, ResourceServer resourceServer, Policy policy,
Map<String, Collection<String>> contextAttributes) {
return new DefaultEvaluation(new ResourcePermission(resource, null, resourceServer), new DefaultEvaluationContext(new Identity() {
@Override
public String getId() {
@ -609,8 +652,19 @@ public class PolicyEvaluationTest extends AbstractAuthzTest {
public Attributes getAttributes() {
return null;
}
}, session), policy, policy, evaluation -> {
}, session) {
}, authorization);
/*
* Allow specific tests to override/add attributes to the context.
*/
@Override
public Map<String, Collection<String>> getBaseAttributes() {
Map<String, Collection<String>> baseAttributes = super.getBaseAttributes();
if (contextAttributes != null) {
baseAttributes.putAll(contextAttributes);
}
return baseAttributes;
}
}, policy, policy, evaluation -> {}, authorization);
}
}