[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.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)))) {
|
||||
|
|
|
@ -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()));
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue