[KEYCLOAK-6853] Make TimePolicyProvider use the kc.date.time_date contextual attribute when evaluating policies
This commit is contained in:
parent
f652b13520
commit
87abe5e648
3 changed files with 72 additions and 6 deletions
|
@ -21,8 +21,10 @@ import java.text.SimpleDateFormat;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
|
import org.keycloak.authorization.attribute.Attributes;
|
||||||
import org.keycloak.authorization.model.Policy;
|
import org.keycloak.authorization.model.Policy;
|
||||||
import org.keycloak.authorization.policy.evaluation.Evaluation;
|
import org.keycloak.authorization.policy.evaluation.Evaluation;
|
||||||
|
import org.keycloak.authorization.policy.evaluation.EvaluationContext;
|
||||||
import org.keycloak.authorization.policy.provider.PolicyProvider;
|
import org.keycloak.authorization.policy.provider.PolicyProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,15 +32,25 @@ import org.keycloak.authorization.policy.provider.PolicyProvider;
|
||||||
*/
|
*/
|
||||||
public class TimePolicyProvider implements 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
|
@Override
|
||||||
public void evaluate(Evaluation evaluation) {
|
public void evaluate(Evaluation evaluation) {
|
||||||
Policy policy = evaluation.getPolicy();
|
Policy policy = evaluation.getPolicy();
|
||||||
SimpleDateFormat dateFormat = new SimpleDateFormat(DEFAULT_DATE_PATTERN);
|
SimpleDateFormat dateFormat = new SimpleDateFormat(DEFAULT_DATE_PATTERN);
|
||||||
Date actualDate = new Date();
|
|
||||||
|
|
||||||
try {
|
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");
|
String notBefore = policy.getConfig().get("nbf");
|
||||||
if (notBefore != null && !"".equals(notBefore)) {
|
if (notBefore != null && !"".equals(notBefore)) {
|
||||||
if (actualDate.before(dateFormat.parse(format(notBefore)))) {
|
if (actualDate.before(dateFormat.parse(format(notBefore)))) {
|
||||||
|
|
|
@ -53,7 +53,7 @@ public class DefaultEvaluationContext implements EvaluationContext {
|
||||||
public Map<String, Collection<String>> getBaseAttributes() {
|
public Map<String, Collection<String>> getBaseAttributes() {
|
||||||
HashMap<String, Collection<String>> attributes = new HashMap<>();
|
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.ip_address", Arrays.asList(this.keycloakSession.getContext().getConnection().getRemoteAddr()));
|
||||||
attributes.put("kc.client.network.host", Arrays.asList(this.keycloakSession.getContext().getConnection().getRemoteHost()));
|
attributes.put("kc.client.network.host", Arrays.asList(this.keycloakSession.getContext().getConnection().getRemoteHost()));
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,10 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.testsuite.authz;
|
package org.keycloak.testsuite.authz;
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
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.ProtocolMapperRepresentation;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
import org.keycloak.representations.idm.authorization.JSPolicyRepresentation;
|
import org.keycloak.representations.idm.authorization.JSPolicyRepresentation;
|
||||||
|
import org.keycloak.representations.idm.authorization.TimePolicyRepresentation;
|
||||||
import org.keycloak.testsuite.runonserver.RunOnServerDeployment;
|
import org.keycloak.testsuite.runonserver.RunOnServerDeployment;
|
||||||
import org.keycloak.testsuite.util.ClientBuilder;
|
import org.keycloak.testsuite.util.ClientBuilder;
|
||||||
import org.keycloak.testsuite.util.GroupBuilder;
|
import org.keycloak.testsuite.util.GroupBuilder;
|
||||||
|
@ -123,6 +127,39 @@ public class PolicyEvaluationTest extends AbstractAuthzTest {
|
||||||
return RunOnServerDeployment.create(AbstractAuthzTest.class);
|
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
|
@Test
|
||||||
public void testCheckUserInGroup() {
|
public void testCheckUserInGroup() {
|
||||||
testingClient.server().run(PolicyEvaluationTest::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) {
|
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() {
|
return new DefaultEvaluation(new ResourcePermission(resource, null, resourceServer), new DefaultEvaluationContext(new Identity() {
|
||||||
@Override
|
@Override
|
||||||
public String getId() {
|
public String getId() {
|
||||||
|
@ -609,8 +652,19 @@ public class PolicyEvaluationTest extends AbstractAuthzTest {
|
||||||
public Attributes getAttributes() {
|
public Attributes getAttributes() {
|
||||||
return null;
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue