All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.spongepowered.api.service.permission.Subject Maven / Gradle / Ivy

There is a newer version: 9.0.0
Show newest version
/*
 * This file is part of SpongeAPI, licensed under the MIT License (MIT).
 *
 * Copyright (c) SpongePowered 
 * Copyright (c) contributors
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package org.spongepowered.api.service.permission;

import org.spongepowered.api.event.Cause;
import org.spongepowered.api.event.EventContext;
import org.spongepowered.api.event.EventContextKeys;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.context.ContextCalculator;
import org.spongepowered.api.service.context.Contextual;
import org.spongepowered.api.util.Tristate;

import java.util.List;
import java.util.Optional;
import java.util.Set;

/**
 * An object which can hold permission data.
 *
 * 

Subjects are objects which hold permission data, in the form of * {@link SubjectData}. They can also be the source of permission requests.

* *

The most common forms of Subject are "users" and "groups", although these * are not the only forms. Anything can hold permission data, and therefore be a * subject.

* *

Permission strings

* *

Authorization checks are made using "permission strings."

* *

Permission strings are hierarchical with each level separated by periods * (full stops). An example of a valid permission string is {@code * example.function}. Inheritance is implicit; that is, if a subject has been * granted {@code example}, then the subject should have also be automatically * granted {@code example.function}, {@code example.another}, {@code * example.deeper.nesting}, and so on. However, implementations may allow * administrators to configure "negation" such that {@code example} and all * child levels would granted but {@code example.access} would denied (for * example).

* *

It is the responsibility of the {@link PermissionService} implementation * to provide this behavior, and resolve the implicit permission node * inheritance explained above when a Subject is queried for permissions. Use * of a {@link NodeTree} is recommended.

* *

Plugins may opt to implement "dynamic" permissions such as {@code * example.region.define.} where {@code region} would depend on * the context of the check. Attention should be made towards the handling of * periods / full stops in such cases.

* *

Due to the implicit inheritance, it is recommended that commands that * allow a user to "apply" an effect to other users use * {@code example.function.self} as the permission for applying this effect * to one's self. This allows administrators to grant * {@code example.function.self} to permit usage on one's self and grant * {@code example.function} to grant usage on other users.

* *

Inheritance

* *

All methods are expected to account for data inherited from parent * subjects. For a representation of the data that the subject explicitly holds, * obtain the {@link SubjectData} for the subject.

* *

Additionally, all methods are expected to account for the defaults * defined in the {@link SubjectCollection} containing this subject, as well * as the defaults set globally in {@link PermissionService#defaults()}.

* *

Contexts

* *

Permission state is calculated using small pieces of information known as * contexts. These are derived from a provided {@link Cause} using * {@link ContextCalculator}s. Subjects have a * {@linkplain #contextCause() default cause} for context calculation, which is * based on the subject's active state.

* *

The relevant active state for subject context may be different depending * on which types of permissions are being checked. Mostly, these will fall into * either global game state or the subject's own state. While * the default implementation of {@link #contextCause()} provides the latter, * some proxy subjects that act as a projection of a subject into a certain * state (such as {@link org.spongepowered.api.command.CommandCause} may choose * to default to the former. The relevant cause stack should be carefully * considered when performing permissions checks.

* *

Use a {@link SubjectCollection} to access instances.

* * @see PermissionService to manage Subjects. */ public interface Subject extends Contextual { /** * Returns the subject collection this subject is a member of. * * @return The appropriate collection */ SubjectCollection containingCollection(); /** * Gets a SubjectReference representing this subject. * * @return A subject reference representing this subject */ SubjectReference asSubjectReference(); /** * Get the game object that may be associated with this subject. * *

This could be a player, system subject, or something else. The return * value of this method should not be stored.

* * @return a potential game object */ Optional associatedObject(); @Override default Cause contextCause() { final /* @Nullable */ Object associated = this.associatedObject().orElse(null); if (associated != null) { return Cause.of(EventContext.builder().add(EventContextKeys.SUBJECT, this).build(), associated); } else { return Contextual.super.contextCause(); } } /** * Returns if this Subject has persistent, non-transient data. * *

If true, this subject should have two distinct stores of SubjectData, * and the non-transient form should be saved between sessions.

* *

If false, this subject will have only one store of SubjectData, which * will not be persisted between sessions.

* * @return If this Subject has persistent, non-transient data. */ boolean isSubjectDataPersisted(); /** * Returns the primary data backing for this Subject. * *

If this Subject is not persisted, this data will not be saved * between sessions.

* *

For subjects which are not persisted, the same store will be returned * by {@link #transientSubjectData()}.

* * @return The primary data backing for this Subject */ SubjectData subjectData(); /** * Returns the transient data backing for this Subject. * *

Transient data is guaranteed to only last for the duration of the * subject's session, and is not persisted.

* *

For subjects which are not persisted, the same store will be returned * by {@link #subjectData()}.

* * @return The transient data backing for this Subject */ SubjectData transientSubjectData(); /** * Test whether the subject is permitted to perform an action given as the * given permission string. * *

This must return the same value as {@link #hasPermission(String, Cause)} * called with the phase tracker's current cause. * * @param permission The permission string * @return True if permission is granted */ default boolean hasPermission(final String permission) { return this.hasPermission(permission, this.contextCause()); } /** * Test whether the subject is permitted to perform an action corresponding * to the given permission string. * *

This must return the same boolean equivalent as * {@link #permissionValue(String, Cause)}.

* * @param permission The permission string * @param cause The cause stack to extract context information from * @return True if permission is granted */ default boolean hasPermission(final String permission, final Cause cause) { return this.permissionValue(permission, cause).asBoolean(); } /** * Test whether the subject is permitted to perform an action corresponding * to the given permission string. * *

This must return the same boolean equivalent as * {@link #permissionValue(String, Cause)}.

* * @param permission The permission string * @param contexts The contexts to calculate permission status in * @return True if permission is granted */ default boolean hasPermission(final String permission, final Set contexts) { return this.permissionValue(permission, contexts).asBoolean(); } /** * Returns the calculated value set for a given permission. * *

It is expected that this method will also account for values * inherited from parent subjects, as well as permission nodes inherited * implicitly from a more generic level.

* *

Additionally, the defaults defined the {@link SubjectCollection} * that holds this subject, as well as defaults defined in * {@link PermissionService#defaults()} should be considered for this * lookup.

* *

This method is likely to be called frequently, so it is desirable * that implementations cache the results to method calls.

* * @param permission The permission to check * @return The tristate result of the check */ default Tristate permissionValue(final String permission) { return this.permissionValue(permission, this.contextCause()); } /** * Returns the calculated value set for a given permission. * *

It is expected that this method will also account for values * inherited from parent subjects, as well as permission nodes inherited * implicitly from a more generic level.

* *

Additionally, the defaults defined the {@link SubjectCollection} * that holds this subject, as well as defaults defined in * {@link PermissionService#defaults()} should be considered for this * lookup.

* *

This method is likely to be called frequently, so it is desirable * that implementations cache the results to method calls.

* * @param permission The permission to check * @param cause The cause to gather context from. * @return The tristate result of the check */ Tristate permissionValue(String permission, Cause cause); /** * Returns the calculated value set for a given permission. * *

It is expected that this method will also account for values * inherited from parent subjects, as well as permission nodes inherited * implicitly from a more generic level.

* *

Additionally, the defaults defined the {@link SubjectCollection} * that holds this subject, as well as defaults defined in * {@link PermissionService#defaults()} should be considered for this * lookup.

* *

This method is likely to be called frequently, so it is desirable * that implementations cache the results to method calls.

* * @param permission The permission to check * @param contexts The contexts to query permission value in * @return The tristate result of the check */ Tristate permissionValue(String permission, Set contexts); /** * Check if this subject is a child of the given parent in the subject's * current context, traversing inheritance. * *

This must return the same value as * {@link #isChildOf(SubjectReference, Cause)} called with the phase * tracker's current cause. * * @param parent The parent to check for inheritance * @return Whether this is a child of the given parent */ default boolean isChildOf(final SubjectReference parent) { return this.isChildOf(parent, this.contextCause()); } /** * Check if this subject is a child of the given parent in the given context * combination, traversing inheritance. * *

It is expected that this method will also account for data from * distant parents, inherited from direct parent subjects. * *

Additionally, the defaults defined the {@link SubjectCollection} * that holds this subject, as well as defaults defined in * {@link PermissionService#defaults()} should be considered for this * lookup.

* * @param parent The parent to check for inheritance * @param cause The cause to gather context from. * @return Whether this is a child of the given parent */ boolean isChildOf(SubjectReference parent, Cause cause); /** * Check if this subject is a child of the given parent in the given context * combination, traversing inheritance. * *

It is expected that this method will also account for data from * distant parents, inherited from direct parent subjects. * *

Additionally, the defaults defined the {@link SubjectCollection} * that holds this subject, as well as defaults defined in * {@link PermissionService#defaults()} should be considered for this * lookup.

* * @param parent The parent to check for inheritance * @param contexts The contexts to query inheritance in * @return Whether this is a child of the given parent */ boolean isChildOf(SubjectReference parent, Set contexts); /** * Return all parents that this group has in its current context * combination. * *

This must include inherited values if the permissions * service supports inheritance.

* *

It must also must return the same value as {@link #parents(Cause)} * * @return An immutable list of parents */ default List parents() { return this.parents(this.contextCause()); } /** * Return all parents that this group has in the given context combination. * *

This must include inherited values if the permissions * service supports inheritance.

* * @param cause The cause to gather context from. * @return An immutable list of parents */ List parents(Cause cause); /** * Return all parents that this group has in the given context combination. * *

This must include inherited values if the permissions * service supports inheritance.

* * @param contexts The cause to gather context from. * @return An immutable list of parents */ List parents(Set contexts); /** * Gets the value of a given option in the subject's current context. * *

This must return the same value as {@link #option(String, Cause)} * called with the phase tracker's current cause. * * @param key The key to get an option by. Case-insensitive. * @return The value of the option, if any is present */ default Optional option(final String key) { return this.option(key, this.contextCause()); } /** * Gets the value of a given option in the given context. * *

It is expected that this method will account for options * inherited from parent subjects. * *

Additionally, the default options defined by the * {@link SubjectCollection} that holds this subject, as well as defaults * defined in {@link PermissionService#defaults()} should be considered * for this lookup. * * @param key The key to get an option by. Case-insensitive. * @param cause The cause to gather context from. * @return The value of the option, if any is present */ Optional option(String key, Cause cause); /** * Gets the value of a given option in the given context. * *

It is expected that this method will account for options * inherited from parent subjects. * *

Additionally, the default options defined by the * {@link SubjectCollection} that holds this subject, as well as defaults * defined in {@link PermissionService#defaults()} should be considered * for this lookup. * * @param key The key to get an option by. Case-insensitive. * @param contexts The context set to use when calculating causes * @return The value of the option, if any is present */ Optional option(String key, Set contexts); }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy