Skip to content

Commit

Permalink
feat: support stream effector (#238)
Browse files Browse the repository at this point in the history
Signed-off-by: Zixuan Liu <nodeces@gmail.com>
  • Loading branch information
nodece committed Nov 21, 2021
1 parent 87e155d commit 51e949a
Show file tree
Hide file tree
Showing 8 changed files with 250 additions and 22 deletions.
5 changes: 5 additions & 0 deletions src/main/java/org/casbin/jcasbin/effect/DefaultEffector.java
Expand Up @@ -74,4 +74,9 @@ public boolean mergeEffects(String expr, Effect[] effects, float[] results) {

return result;
}

@Override
public StreamEffector newStreamEffector(String expr) {
return new DefaultStreamEffector(expr);
}
}
67 changes: 67 additions & 0 deletions src/main/java/org/casbin/jcasbin/effect/DefaultStreamEffector.java
@@ -0,0 +1,67 @@
// Copyright 2021 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package org.casbin.jcasbin.effect;

public class DefaultStreamEffector implements StreamEffector {
private final String expr;
private boolean done = false;
private boolean effect = false;

public DefaultStreamEffector(String expr) {
this.expr = expr;
}

@Override
public StreamEffectorResult current() {
return new DefaultStreamEffectorResult(effect, done);
}

@Override
public boolean push(Effect eft, int currentIndex, int policySize) {
switch (this.expr) {
case "some(where (p_eft == allow))":
if (eft == Effect.Allow) {
this.effect = true;
this.done = true;
}
break;
case "!some(where (p_eft == deny))":
this.effect = true;
if (eft == Effect.Deny) {
this.effect = false;
this.done = true;
}
break;
case "some(where (p_eft == allow)) && !some(where (p_eft == deny))":
if (eft == Effect.Allow) {
this.effect = true;
} else if (eft == Effect.Deny) {
this.effect = false;
this.done = true;
}
break;
case "priority(p_eft) || deny":
if (eft != Effect.Indeterminate) {
this.effect = eft == Effect.Allow;
this.done = true;
}
break;
default:
throw new UnsupportedOperationException("unsupported effect");
}

return this.done;
}
}
@@ -0,0 +1,46 @@
// Copyright 2021 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package org.casbin.jcasbin.effect;

public class DefaultStreamEffectorResult implements StreamEffectorResult {
private boolean done;
private boolean effect;

public DefaultStreamEffectorResult(){

}

public DefaultStreamEffectorResult(boolean effect, boolean done) {
this.effect = effect;
this.done = done;
}

@Override
public boolean hasEffect() {
return effect;
}

public boolean isDone() {
return done;
}

public void setEffect(boolean effect) {
this.effect = effect;
}

public void setDone(boolean done) {
this.done = done;
}
}
6 changes: 6 additions & 0 deletions src/main/java/org/casbin/jcasbin/effect/Effector.java
Expand Up @@ -25,6 +25,12 @@ public interface Effector {
* @param effects the effects of all matched rules.
* @param results the matcher results of all matched rules.
* @return the final effect.
*
* @deprecated use newStreamEffector instead of this.
*/
boolean mergeEffects(String expr, Effect[] effects, float[] results);

default StreamEffector newStreamEffector(String expr) {
throw new UnsupportedOperationException("Not implemented");
}
}
21 changes: 21 additions & 0 deletions src/main/java/org/casbin/jcasbin/effect/StreamEffector.java
@@ -0,0 +1,21 @@
// Copyright 2021 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package org.casbin.jcasbin.effect;

// StreamEffector provides a stream interface for effector.
public interface StreamEffector {
StreamEffectorResult current();
boolean push(Effect effect, int currentIndex, int policySize);
}
20 changes: 20 additions & 0 deletions src/main/java/org/casbin/jcasbin/effect/StreamEffectorResult.java
@@ -0,0 +1,20 @@
// Copyright 2021 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package org.casbin.jcasbin.effect;

public interface StreamEffectorResult {
boolean hasEffect();
boolean isDone();
}
@@ -0,0 +1,21 @@
// Copyright 2018 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package org.casbin.jcasbin.exception;

public class CasbinEffectorException extends RuntimeException {
public CasbinEffectorException(Throwable throwable) {
super(throwable);
}
}
86 changes: 64 additions & 22 deletions src/main/java/org/casbin/jcasbin/main/CoreEnforcer.java
Expand Up @@ -17,26 +17,31 @@
import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.AviatorEvaluatorInstance;
import com.googlecode.aviator.Expression;
import com.googlecode.aviator.lexer.token.OperatorType;
import com.googlecode.aviator.runtime.type.AviatorFunction;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.casbin.jcasbin.effect.DefaultEffector;
import org.casbin.jcasbin.effect.Effect;
import org.casbin.jcasbin.effect.Effector;
import org.casbin.jcasbin.effect.StreamEffector;
import org.casbin.jcasbin.effect.StreamEffectorResult;
import org.casbin.jcasbin.exception.CasbinAdapterException;
import org.casbin.jcasbin.exception.CasbinEffectorException;
import org.casbin.jcasbin.exception.CasbinMatcherException;
import org.casbin.jcasbin.model.Assertion;
import org.casbin.jcasbin.model.FunctionMap;
import org.casbin.jcasbin.model.Model;
import org.casbin.jcasbin.persist.*;
import org.casbin.jcasbin.persist.Adapter;
import org.casbin.jcasbin.persist.Dispatcher;
import org.casbin.jcasbin.persist.FilteredAdapter;
import org.casbin.jcasbin.persist.Watcher;
import org.casbin.jcasbin.persist.WatcherEx;
import org.casbin.jcasbin.rbac.DefaultRoleManager;
import org.casbin.jcasbin.rbac.RoleManager;
import org.casbin.jcasbin.util.BuiltInFunctions;
import org.casbin.jcasbin.util.Util;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* CoreEnforcer defines the core functionality of an enforcer.
*/
Expand Down Expand Up @@ -427,6 +432,15 @@ private boolean enforce(String matcher, Object... rvals) {
expString = Util.convertInSyntax(expString);
Expression expression = aviatorEval.compile(expString, true);

StreamEffector streamEffector = null;
try {
streamEffector = this.eft.newStreamEffector(model.model.get("e").get("e").value);
} catch (Exception e) {
if (!(e instanceof UnsupportedOperationException)) {
throw new CasbinEffectorException(e);
}
}

Effect[] policyEffects;
float[] matcherResults;
int policyLen;
Expand All @@ -452,19 +466,26 @@ private boolean enforce(String matcher, Object... rvals) {
if (result instanceof Boolean) {
if (!((boolean) result)) {
policyEffects[i] = Effect.Indeterminate;
} else {
policyEffects[i] = Effect.Allow;
}
if (streamEffector == null) {
continue;
}
} else if (result instanceof Float) {
if ((float) result == 0) {
policyEffects[i] = Effect.Indeterminate;
continue;
} else {
matcherResults[i] = (float) result;
policyEffects[i] = Effect.Allow;
}
if (streamEffector == null) {
continue;
}
} else {
throw new CasbinMatcherException("matcher result should be bool, int or float");
}
if (parameters.containsKey("p_eft")) {
if (policyEffects[i] == Effect.Allow && parameters.containsKey("p_eft")) {
String eft = (String) parameters.get("p_eft");
if ("allow".equals(eft)) {
policyEffects[i] = Effect.Allow;
Expand All @@ -473,12 +494,17 @@ private boolean enforce(String matcher, Object... rvals) {
} else {
policyEffects[i] = Effect.Indeterminate;
}
} else {
policyEffects[i] = Effect.Allow;
}

if ("priority(p_eft) || deny".equals(model.model.get("e").get("e").value)) {
break;
if (streamEffector != null) {
boolean done = streamEffector.push(policyEffects[i], i, policyLen);
if (done) {
break;
}
} else {
if ("priority(p_eft) || deny".equals(model.model.get("e").get("e").value)) {
break;
}
}
}
} else {
Expand All @@ -498,14 +524,28 @@ private boolean enforce(String matcher, Object... rvals) {
Object result = expression.execute(parameters);
// Util.logPrint("Result: " + result);

if ((boolean) result) {
policyEffects[0] = Effect.Allow;
if (streamEffector != null) {
if ((boolean) result) {
streamEffector.push(Effect.Allow, 0, 1);
} else {
streamEffector.push(Effect.Indeterminate, 0, 1);
}
} else {
policyEffects[0] = Effect.Indeterminate;
if ((boolean) result) {
policyEffects[0] = Effect.Allow;
} else {
policyEffects[0] = Effect.Indeterminate;
}
}
}

boolean result = eft.mergeEffects(model.model.get("e").get("e").value, policyEffects, matcherResults);
boolean result;

if (streamEffector != null && streamEffector.current() != null) {
result = streamEffector.current().hasEffect();
} else {
result = eft.mergeEffects(model.model.get("e").get("e").value, policyEffects, matcherResults);
}

StringBuilder reqStr = new StringBuilder("Request: ");
for (int i = 0; i < rvals.length; i++) {
Expand Down Expand Up @@ -548,19 +588,21 @@ public boolean enforceWithMatcher(String matcher, Object... rvals) {
return enforce(matcher, rvals);
}

private void getRTokens(Map<String, Object> parameters, Object ...rvals) {
for(String rKey : model.model.get("r").keySet()) {
if(!(rvals.length == model.model.get("r").get(rKey).tokens.length)) { continue; }
for (int j = 0; j < model.model.get("r").get(rKey).tokens.length; j ++) {
private void getRTokens(Map<String, Object> parameters, Object... rvals) {
for (String rKey : model.model.get("r").keySet()) {
if (!(rvals.length == model.model.get("r").get(rKey).tokens.length)) {
continue;
}
for (int j = 0; j < model.model.get("r").get(rKey).tokens.length; j++) {
String token = model.model.get("r").get(rKey).tokens[j];
parameters.put(token, rvals[j]);
}

}
}

public boolean validateEnforce(Object... rvals){
return validateEnforceSection("r",rvals);
public boolean validateEnforce(Object... rvals) {
return validateEnforceSection("r", rvals);
}

private boolean validateEnforceSection(String section, Object... rvals) {
Expand Down

0 comments on commit 51e949a

Please sign in to comment.