Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you 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.elasticsearch.client.security.support.expressiondsl;

import org.elasticsearch.common.xcontent.ToXContentObject;

/**
* Implementations of this interface represent an expression used for user role mapping
* that can later be resolved to a boolean value.
*/
public interface RoleMapperExpression extends ToXContentObject {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you 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.elasticsearch.client.security.support.expressiondsl.expressions;

import org.elasticsearch.client.security.support.expressiondsl.RoleMapperExpression;

import java.util.ArrayList;
import java.util.List;

/**
* An expression that evaluates to <code>true</code> if-and-only-if all its children
* evaluate to <code>true</code>.
* An <em>all</em> expression with no children is always <code>true</code>.
*/
public final class AllRoleMapperExpression extends CompositeRoleMapperExpression {

private AllRoleMapperExpression(String name, RoleMapperExpression[] elements) {
super(name, elements);
}

public static Builder builder() {
return new Builder();
}

public static final class Builder {
private List<RoleMapperExpression> elements = new ArrayList<>();

public Builder addExpression(final RoleMapperExpression expression) {
assert expression != null : "expression cannot be null";
elements.add(expression);
return this;
}

public AllRoleMapperExpression build() {
return new AllRoleMapperExpression(CompositeType.ALL.getName(), elements.toArray(new RoleMapperExpression[0]));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you 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.elasticsearch.client.security.support.expressiondsl.expressions;

import org.elasticsearch.client.security.support.expressiondsl.RoleMapperExpression;

import java.util.ArrayList;
import java.util.List;

/**
* An expression that evaluates to <code>true</code> if at least one of its children
* evaluate to <code>true</code>.
* An <em>any</em> expression with no children is never <code>true</code>.
*/
public final class AnyRoleMapperExpression extends CompositeRoleMapperExpression {

private AnyRoleMapperExpression(String name, RoleMapperExpression[] elements) {
super(name, elements);
}

public static Builder builder() {
return new Builder();
}

public static final class Builder {
private List<RoleMapperExpression> elements = new ArrayList<>();

public Builder addExpression(final RoleMapperExpression expression) {
assert expression != null : "expression cannot be null";
elements.add(expression);
return this;
}

public AnyRoleMapperExpression build() {
return new AnyRoleMapperExpression(CompositeType.ANY.getName(), elements.toArray(new RoleMapperExpression[0]));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you 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.elasticsearch.client.security.support.expressiondsl.expressions;

import org.elasticsearch.client.security.support.expressiondsl.RoleMapperExpression;
import org.elasticsearch.common.xcontent.XContentBuilder;

import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
* Expression of role mapper expressions which can be combined by operators like AND, OR
* <p>
* Expression builder example:
* <pre>
* {@code
* final RoleMapperExpression allExpression = AllRoleMapperExpression.builder()
.addExpression(AnyRoleMapperExpression.builder()
.addExpression(FieldRoleMapperExpression.ofUsername("[email protected]"))
.addExpression(FieldRoleMapperExpression.ofUsername("[email protected]"))
.build())
.addExpression(FieldRoleMapperExpression.ofMetadata("metadata.location", "AMER"))
.addExpression(new ExceptRoleMapperExpression(FieldRoleMapperExpression.ofUsername("[email protected]")))
.build();
* }
* </pre>
*/
public abstract class CompositeRoleMapperExpression implements RoleMapperExpression {
private final String name;
private final List<RoleMapperExpression> elements;

CompositeRoleMapperExpression(final String name, final RoleMapperExpression... elements) {
assert name != null : "field name cannot be null";
assert elements != null : "at least one field expression is required";
this.name = name;
this.elements = Collections.unmodifiableList(Arrays.asList(elements));
}

public String getName() {
return this.getName();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/return this.getName();/return this.name;/
Noticed this when reviewing #34171 , maybe you can correct this there.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, I will address in the other review for the create role mapping API. Thank you.

}

public List<RoleMapperExpression> getElements() {
return elements;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}

final CompositeRoleMapperExpression that = (CompositeRoleMapperExpression) o;
if (Objects.equals(this.getName(), that.getName()) == false) {
return false;
}
return Objects.equals(this.getElements(), that.getElements());
}

@Override
public int hashCode() {
return Objects.hash(name, elements);
}

@Override
public XContentBuilder toXContent(final XContentBuilder builder, final Params params) throws IOException {
builder.startObject();
builder.startArray(name);
for (RoleMapperExpression e : elements) {
e.toXContent(builder, params);
}
builder.endArray();
return builder.endObject();
}

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you 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.elasticsearch.client.security.support.expressiondsl.expressions;

import org.elasticsearch.common.ParseField;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public enum CompositeType {

ANY("any"), ALL("all"), EXCEPT("except");

private static Map<String, CompositeType> nameToType = Collections.unmodifiableMap(initialize());
private ParseField field;

CompositeType(String name) {
this.field = new ParseField(name);
}

public String getName() {
return field.getPreferredName();
}

public ParseField getParseField() {
return field;
}

public static CompositeType fromName(String name) {
return nameToType.get(name);
}

private static Map<String, CompositeType> initialize() {
Map<String, CompositeType> map = new HashMap<>();
for (CompositeType field : values()) {
map.put(field.getName(), field);
}
return map;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you 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.elasticsearch.client.security.support.expressiondsl.expressions;

import org.elasticsearch.client.security.support.expressiondsl.RoleMapperExpression;
import org.elasticsearch.common.xcontent.XContentBuilder;

import java.io.IOException;

/**
* A negating expression. That is, this expression evaluates to <code>true</code> if-and-only-if
* its delegate expression evaluate to <code>false</code>.
* Syntactically, <em>except</em> expressions are intended to be children of <em>all</em>
* expressions ({@link AllRoleMapperExpression}).
*/
public final class ExceptRoleMapperExpression extends CompositeRoleMapperExpression {

public ExceptRoleMapperExpression(final RoleMapperExpression expression) {
super(CompositeType.EXCEPT.getName(), expression);
}

@Override
public XContentBuilder toXContent(final XContentBuilder builder, final Params params) throws IOException {
builder.startObject();
builder.field(CompositeType.EXCEPT.getName());
builder.value(getElements().get(0));
return builder.endObject();
}

}
Loading