Skip to content

Commit

Permalink
authorize third party blocks
Browse files Browse the repository at this point in the history
  • Loading branch information
Geal committed Jan 5, 2024
1 parent 6878e82 commit 32a53d4
Show file tree
Hide file tree
Showing 12 changed files with 137 additions and 60 deletions.
3 changes: 1 addition & 2 deletions src/main/java/com/clevercloud/biscuit/crypto/PublicKey.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,7 @@ public Schema.PublicKey serialize() {

static public PublicKey deserialize(Schema.PublicKey pk) throws Error.FormatError.DeserializationError {
if(!pk.hasAlgorithm() || !pk.hasKey() || pk.getAlgorithm() != Algorithm.Ed25519) {
throw new Error.FormatError.DeserializationError("Invalid " +
"public key");
throw new Error.FormatError.DeserializationError("Invalid public key");
}

return new PublicKey(pk.getAlgorithm(), pk.getKey().toByteArray());
Expand Down
5 changes: 2 additions & 3 deletions src/main/java/com/clevercloud/biscuit/datalog/Combinator.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public Option<Tuple2<Origin, Map<Long, Term>>> getNext() {
// we iterate over the facts that match the current predicate
if (this.currentFacts.hasNext()) {
final Tuple2<Origin, Fact> t = this.currentFacts.next();
Origin currentOrigin = t._1;
Origin currentOrigin = t._1.clone();
Fact fact = t._2;

// create a new MatchedVariables in which we fix variables we could unify from our first predicate and the current fact
Expand Down Expand Up @@ -129,8 +129,7 @@ public Option<Tuple2<Origin, Map<Long, Term>>> getNext() {

if (opt.isDefined()) {
Tuple2<Origin, Map<Long, Term>> t = opt.get();
t._1.union(currentOrigin);
return Option.some(t);
return Option.some(new Tuple2<>(t._1.union(currentOrigin), t._2));
} else {
currentOrigin = null;
currentIt = null;
Expand Down
6 changes: 4 additions & 2 deletions src/main/java/com/clevercloud/biscuit/datalog/Origin.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@ public void add(long i) {
inner.add(i);
}

public void union(Origin other) {
this.inner.addAll(other.inner);
public Origin union(Origin other) {
Origin o = this.clone();
o.inner.addAll(other.inner);
return o;
}

public Origin clone() {
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/com/clevercloud/biscuit/datalog/Scope.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,12 @@ static public Either<Error.FormatError, Scope> deserialize(Schema.Scope scope) {
}
return Left(new Error.FormatError.DeserializationError("invalid Scope"));
}

@Override
public String toString() {
return "Scope{" +
"kind=" + kind +
", publicKey=" + publicKey +
'}';
}
}
16 changes: 15 additions & 1 deletion src/main/java/com/clevercloud/biscuit/datalog/SymbolTable.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ private String fromEpochIsoDate(long epochSec) {
"query"
);
public final List<String> symbols;
public final List<PublicKey> publicKeys;
private final List<PublicKey> publicKeys;

public long insert(final String symbol) {
int index = this.defaultSymbols.indexOf(symbol);
Expand All @@ -81,6 +81,13 @@ public long insert(final String symbol) {
public int currentOffset() {
return this.symbols.size();
}
public int currentPublicKeyOffset() {
return this.publicKeys.size();
}

public List<PublicKey> publicKeys() {
return publicKeys;
}

public long insert(final PublicKey publicKey) {
int index = this.publicKeys.indexOf(publicKey);
Expand Down Expand Up @@ -278,6 +285,13 @@ public SymbolTable(SymbolTable s) {
publicKeys.addAll(s.publicKeys);
}

public SymbolTable(List<String> symbols, List<PublicKey> publicKeys) {
this.symbols = new ArrayList<>();
this.symbols.addAll(symbols);
this.publicKeys = new ArrayList<>();
this.publicKeys.addAll(publicKeys);
}

public List<String> getAllSymbols() {
ArrayList<String> allSymbols = new ArrayList<>();
allSymbols.addAll(defaultSymbols);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,11 @@ public static TrustedOrigins fromScopes(List<Scope> ruleScopes,
public boolean contains(Origin factOrigin) {
return this.inner.inner.containsAll(factOrigin.inner);
}

@Override
public String toString() {
return "TrustedOrigins{" +
"inner=" + inner +
'}';
}
}
94 changes: 66 additions & 28 deletions src/main/java/com/clevercloud/biscuit/token/Authorizer.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.clevercloud.biscuit.token;

import com.clevercloud.biscuit.crypto.PublicKey;
import com.clevercloud.biscuit.datalog.*;
import com.clevercloud.biscuit.datalog.Scope;
import com.clevercloud.biscuit.error.Error;
Expand Down Expand Up @@ -107,6 +108,11 @@ public void update_on_token() throws Error.FailedLogic {
throw new Error.FailedLogic(new LogicError.InvalidBlockRule(0, token.symbols.print_rule(converted_rule)));
}
}
this.publicKeyToBlockId.putAll(token.publicKeyToBlockId);
for(Long keyId: token.publicKeyToBlockId.keySet()) {
PublicKey pk = token.symbols.get_pk((int) keyId.longValue()).get();
this.symbols.insert(pk);
}
}
}

Expand Down Expand Up @@ -335,8 +341,16 @@ public Long authorize(RunLimits limits) throws Error {
if (token != null) {
for (com.clevercloud.biscuit.datalog.Fact fact : token.authority.facts) {
com.clevercloud.biscuit.datalog.Fact converted_fact = Fact.convert_from(fact, token.symbols).convert(this.symbols);
world.add_fact(authorizerOrigin, converted_fact);
world.add_fact(new Origin(0), converted_fact);
}

TrustedOrigins authorityTrustedOrigins = TrustedOrigins.fromScopes(
token.authority.scopes,
TrustedOrigins.defaultOrigins(),
0,
this.publicKeyToBlockId
);

for (com.clevercloud.biscuit.datalog.Rule rule : token.authority.rules) {
com.clevercloud.biscuit.token.builder.Rule _rule = Rule.convert_from(rule, token.symbols);
com.clevercloud.biscuit.datalog.Rule converted_rule = _rule.convert(this.symbols);
Expand All @@ -345,6 +359,50 @@ public Long authorize(RunLimits limits) throws Error {
if(res.isLeft()){
throw new Error.FailedLogic(new LogicError.InvalidBlockRule(0, token.symbols.print_rule(converted_rule)));
}
TrustedOrigins ruleTrustedOrigins = TrustedOrigins.fromScopes(
converted_rule.scopes(),
authorityTrustedOrigins,
0,
this.publicKeyToBlockId
);
world.add_rule((long) 0, ruleTrustedOrigins, converted_rule);
}

for (int i = 0; i < token.blocks.size(); i++) {
Block block = token.blocks.get(i);
TrustedOrigins blockTrustedOrigins = TrustedOrigins.fromScopes(
block.scopes,
TrustedOrigins.defaultOrigins(),
i + 1,
this.publicKeyToBlockId
);
SymbolTable blockSymbols = token.symbols;

if (block.externalKey.isDefined()) {
blockSymbols = new SymbolTable(block.symbols.symbols, token.symbols.publicKeys());
}

for (com.clevercloud.biscuit.datalog.Fact fact : block.facts) {
com.clevercloud.biscuit.datalog.Fact converted_fact = Fact.convert_from(fact, blockSymbols).convert(this.symbols);
world.add_fact(new Origin(i + 1), converted_fact);
}

for (com.clevercloud.biscuit.datalog.Rule rule : block.rules) {
com.clevercloud.biscuit.token.builder.Rule _rule = Rule.convert_from(rule, blockSymbols);
com.clevercloud.biscuit.datalog.Rule converted_rule = _rule.convert(this.symbols);

Either<String, Rule> res = _rule.validate_variables();
if (res.isLeft()) {
throw new Error.FailedLogic(new LogicError.InvalidBlockRule(0, this.symbols.print_rule(converted_rule)));
}
TrustedOrigins ruleTrustedOrigins = TrustedOrigins.fromScopes(
converted_rule.scopes(),
blockTrustedOrigins,
i + 1,
this.publicKeyToBlockId
);
world.add_rule((long) i + 1, ruleTrustedOrigins, converted_rule);
}
}
}

Expand Down Expand Up @@ -398,7 +456,7 @@ public Long authorize(RunLimits limits) throws Error {
for (int j = 0; j < token.authority.checks.size(); j++) {
boolean successful = false;

Check c = Check.convert_from(token.authority.checks.get(j), symbols);
Check c = Check.convert_from(token.authority.checks.get(j), token.symbols);
com.clevercloud.biscuit.datalog.Check check = c.convert(symbols);

for (int k = 0; k < check.queries().size(); k++) {
Expand Down Expand Up @@ -441,13 +499,13 @@ public Long authorize(RunLimits limits) throws Error {

for (int j = 0; j < policy.queries.size(); j++) {
com.clevercloud.biscuit.datalog.Rule query = policy.queries.get(j).convert(symbols);
TrustedOrigins ruleTrustedOrigins = TrustedOrigins.fromScopes(
TrustedOrigins policyTrustedOrigins = TrustedOrigins.fromScopes(
query.scopes(),
authorizerTrustedOrigins,
Long.MAX_VALUE,
this.publicKeyToBlockId
);
boolean res = world.query_match(query, Long.MAX_VALUE, ruleTrustedOrigins, symbols);
boolean res = world.query_match(query, Long.MAX_VALUE, policyTrustedOrigins, symbols);

if (Instant.now().compareTo(timeLimit) >= 0) {
throw new Error.Timeout();
Expand All @@ -473,35 +531,15 @@ public Long authorize(RunLimits limits) throws Error {
i+1,
this.publicKeyToBlockId
);

for (com.clevercloud.biscuit.datalog.Fact fact : b.facts) {
com.clevercloud.biscuit.datalog.Fact converted_fact = Fact.convert_from(fact, token.symbols).convert(this.symbols);
world.add_fact(new Origin(i+1), converted_fact);
SymbolTable blockSymbols = token.symbols;
if(b.externalKey.isDefined()) {
blockSymbols = new SymbolTable(b.symbols.symbols, token.symbols.publicKeys());
}

for (com.clevercloud.biscuit.datalog.Rule rule : b.rules) {
com.clevercloud.biscuit.token.builder.Rule _rule = Rule.convert_from(rule, token.symbols);
com.clevercloud.biscuit.datalog.Rule converted_rule = _rule.convert(this.symbols);

Either<String,Rule> res = _rule.validate_variables();
if(res.isLeft()){
throw new Error.FailedLogic(new LogicError.InvalidBlockRule(0, token.symbols.print_rule(converted_rule)));
}
TrustedOrigins ruleTrustedOrigins = TrustedOrigins.fromScopes(
converted_rule.scopes(),
blockTrustedOrigins,
i+1,
this.publicKeyToBlockId
);
world.add_rule((long)i+1, ruleTrustedOrigins, converted_rule);
}

world.run(limits, symbols);

for (int j = 0; j < b.checks.size(); j++) {
boolean successful = false;

Check c = Check.convert_from(b.checks.get(j),symbols);
Check c = Check.convert_from(b.checks.get(j), blockSymbols);
com.clevercloud.biscuit.datalog.Check check = c.convert(symbols);

for (int k = 0; k < check.queries().size(); k++) {
Expand Down
17 changes: 12 additions & 5 deletions src/main/java/com/clevercloud/biscuit/token/Block.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public class Block {
final List<Check> checks;
final List<Scope> scopes;
final List<PublicKey> publicKeys;
final Option<PublicKey> externalKey;
final long version;

/**
Expand All @@ -43,6 +44,7 @@ public Block(SymbolTable base_symbols) {
this.checks = new ArrayList<>();
this.scopes = new ArrayList<>();
this.publicKeys = new ArrayList<>();
this.externalKey = Option.none();
this.version = SerializedBiscuit.MAX_SCHEMA_VERSION;
}

Expand All @@ -54,7 +56,7 @@ public Block(SymbolTable base_symbols) {
* @param checks
*/
public Block(SymbolTable base_symbols, String context, List<Fact> facts, List<Rule> rules, List<Check> checks,
List<Scope> scopes, List<PublicKey> publicKeys, int version) {
List<Scope> scopes, List<PublicKey> publicKeys, Option<PublicKey> externalKey, int version) {
this.symbols = base_symbols;
this.context = context;
this.facts = facts;
Expand All @@ -63,6 +65,7 @@ public Block(SymbolTable base_symbols, String context, List<Fact> facts, List<Ru
this.scopes = scopes;
this.version = version;
this.publicKeys = publicKeys;
this.externalKey = externalKey;
}

public SymbolTable symbols() {
Expand All @@ -87,6 +90,10 @@ public String print(SymbolTable symbol_table) {
s.append(this.symbols.symbols);
s.append("\n\t\tcontext: ");
s.append(this.context);
if(this.externalKey.isDefined()) {
s.append("\n\t\texternal key: ");
s.append(this.externalKey.get().toString());
}
s.append("\n\t\tfacts: [");
for (Fact f : this.facts) {
s.append("\n\t\t\t");
Expand Down Expand Up @@ -153,7 +160,7 @@ public Schema.Block serialize() {
* @param b
* @return
*/
static public Either<Error.FormatError, Block> deserialize(Schema.Block b) {
static public Either<Error.FormatError, Block> deserialize(Schema.Block b, Option<PublicKey> externalKey) {
int version = b.getVersion();
if (version < SerializedBiscuit.MIN_SCHEMA_VERSION || version > SerializedBiscuit.MAX_SCHEMA_VERSION) {
return Left(new Error.FormatError.Version(SerializedBiscuit.MIN_SCHEMA_VERSION, SerializedBiscuit.MAX_SCHEMA_VERSION, version));
Expand Down Expand Up @@ -227,7 +234,7 @@ static public Either<Error.FormatError, Block> deserialize(Schema.Block b) {
return Left(e);
}

return Right(new Block(symbols, b.getContext(), facts, rules, checks, scopes, publicKeys, version));
return Right(new Block(symbols, b.getContext(), facts, rules, checks, scopes, publicKeys, externalKey, version));
}

/**
Expand All @@ -236,10 +243,10 @@ static public Either<Error.FormatError, Block> deserialize(Schema.Block b) {
* @param slice
* @return
*/
static public Either<Error.FormatError, Block> from_bytes(byte[] slice) {
static public Either<Error.FormatError, Block> from_bytes(byte[] slice, Option<PublicKey> externalKey) {
try {
Schema.Block data = Schema.Block.parseFrom(slice);
return Block.deserialize(data);
return Block.deserialize(data, externalKey);
} catch (InvalidProtocolBufferException e) {
return Left(new Error.FormatError.DeserializationError(e.toString()));
}
Expand Down
10 changes: 5 additions & 5 deletions src/main/java/com/clevercloud/biscuit/token/builder/Biscuit.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ public class Biscuit {
public Biscuit(final SecureRandom rng, final KeyPair root, SymbolTable base_symbols) {
this.rng = rng;
this.root = root;
this.symbol_start = base_symbols.symbols.size();
this.publicKeyStart = base_symbols.publicKeys.size();
this.symbol_start = base_symbols.currentOffset();
this.publicKeyStart = base_symbols.currentPublicKeyOffset();
this.symbols = new SymbolTable(base_symbols);
this.context = "";
this.facts = new ArrayList<>();
Expand Down Expand Up @@ -145,14 +145,14 @@ public com.clevercloud.biscuit.token.Biscuit build() throws Error {
}

List<PublicKey> publicKeys = new ArrayList<>();
for (int i = this.publicKeyStart; i < this.symbols.publicKeys.size(); i++) {
publicKeys.add(this.symbols.publicKeys.get(i));
for (int i = this.publicKeyStart; i < this.symbols.currentPublicKeyOffset(); i++) {
publicKeys.add(this.symbols.publicKeys().get(i));
}

SchemaVersion schemaVersion = new SchemaVersion(this.facts, this.rules, this.checks, this.scopes);

Block authority_block = new com.clevercloud.biscuit.token.Block(symbols, context, this.facts, this.rules,
this.checks, scopes, publicKeys, schemaVersion.version());
this.checks, scopes, publicKeys, Option.none(), schemaVersion.version());

if (this.root_key_id.isDefined()) {
return make(this.rng, this.root, this.root_key_id.get(), base_symbols, authority_block);
Expand Down
11 changes: 6 additions & 5 deletions src/main/java/com/clevercloud/biscuit/token/builder/Block.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.clevercloud.biscuit.error.Error;
import io.vavr.Tuple2;
import io.vavr.control.Either;
import io.vavr.control.Option;

import static com.clevercloud.biscuit.datalog.Check.Kind.One;
import static com.clevercloud.biscuit.token.builder.Utils.*;
Expand All @@ -33,8 +34,8 @@ public class Block {

public Block(long index, SymbolTable base_symbols) {
this.index = index;
this.symbol_start = base_symbols.symbols.size();
this.publicKeyStart = base_symbols.publicKeys.size();
this.symbol_start = base_symbols.currentOffset();
this.publicKeyStart = base_symbols.currentPublicKeyOffset();
this.symbols = new SymbolTable(base_symbols);
this.context = "";
this.facts = new ArrayList<>();
Expand Down Expand Up @@ -115,14 +116,14 @@ public com.clevercloud.biscuit.token.Block build() {
}

List<PublicKey> publicKeys = new ArrayList<>();
for (int i = this.publicKeyStart; i < this.symbols.publicKeys.size(); i++) {
publicKeys.add(this.symbols.publicKeys.get(i));
for (int i = this.publicKeyStart; i < this.symbols.currentPublicKeyOffset(); i++) {
publicKeys.add(this.symbols.publicKeys().get(i));
}

SchemaVersion schemaVersion = new SchemaVersion(this.facts, this.rules, this.checks, this.scopes);

return new com.clevercloud.biscuit.token.Block(symbols, this.context, this.facts, this.rules, this.checks,
this.scopes, publicKeys, schemaVersion.version());
this.scopes, publicKeys, Option.none(), schemaVersion.version());
}

public Block check_right(String right) {
Expand Down
Loading

0 comments on commit 32a53d4

Please sign in to comment.