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

sirius.web.security.UserInfo Maven / Gradle / Ivy

There is a newer version: 22.2.3
Show newest version
/*
 * Made with all the love in the world
 * by scireum in Remshalden, Germany
 *
 * Copyright by scireum GmbH
 * http://www.scireum.de - [email protected]
 */

package sirius.web.security;

import sirius.kernel.commons.Strings;
import sirius.kernel.di.transformers.Composable;
import sirius.kernel.di.transformers.Transformable;
import sirius.kernel.health.Exceptions;

import javax.annotation.CheckReturnValue;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collections;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;

/**
 * Represents an user.
 * 

* A user is authenticated using a {@link UserManager}. To obtain or modify the current user, use {@link * UserContext#getCurrentUser()} or {@link UserContext#setCurrentUser(UserInfo)}. */ public class UserInfo extends Composable { /** * This permission represents a user which was successfully authenticated by its user manager. */ public static final String PERMISSION_LOGGED_IN = "flag-logged-in"; /** * Fallback user if no user is currently available. This user has no permissions. */ public static final UserInfo NOBODY = Builder.createUser("ANONYMOUS").withUsername("(no user)").build(); /** * Represents a special permission which is never granted - therefore {@link #hasPermission(String)} will always * return false. */ private static final String DISABLED = "disabled"; /** * Represents a special permission which is always granted - therefore {@link #hasPermission(String)} will always * return true. */ private static final String ENABLED = "enabled"; protected String tenantId; protected String tenantName; protected String userId; protected String username; protected String lang; protected Set permissions = null; protected Function settingsSupplier; protected Function userSupplier; /** * Builder pattern to create a new {@link UserInfo}. */ public static class Builder { private UserInfo user; private Builder() { } /** * Creates a new builder and initializes it with an id for the user. * * @param id the id of the user to build. * @return the builder itself for fluent method calls */ @CheckReturnValue public static Builder createUser(@Nonnull String id) { Builder builder = new Builder(); builder.user = new UserInfo(); builder.user.userId = id; return builder; } /** * Sets the name of the user. * * @param name the name of the user. * @return the builder itself for fluent method calls */ public Builder withUsername(String name) { verifyState(); user.username = name; return this; } /** * Sets the id of the tenant the user belongs to. * * @param id the id of the tenant * @return the builder itself for fluent method calls */ public Builder withTenantId(String id) { verifyState(); user.tenantId = id; return this; } /** * Sets the name of the tenant the user belongs to. * * @param name the name of the tenant * @return the builder itself for fluent method calls */ public Builder withTenantName(String name) { verifyState(); user.tenantName = name; return this; } private void verifyState() { if (user == null) { throw new IllegalStateException("UserInfo already built."); } } /** * Sets the language code of the user. * * @param lang a two-letter language code which should be understood by {@link sirius.kernel.nls.NLS}. * @return the builder itself for fluent method calls */ public Builder withLang(String lang) { verifyState(); user.lang = lang; return this; } /** * Sets the permissions granted to the user. * * @param permissions the set of permissions granted to the user * @return the builder itself for fluent method calls */ public Builder withPermissions(Set permissions) { verifyState(); user.permissions = permissions; return this; } /** * Sets a config supplier which can provide an individual configuration for the current user. * * @param settingsSupplier the function which fetches or computes the configuration for this user on demand. * @return the builder itself for fluent method calls */ public Builder withSettingsSupplier(Function settingsSupplier) { verifyState(); user.settingsSupplier = settingsSupplier; return this; } /** * Sets a user supplier which returns the underlying user object (e.g. a database entity). * * @param userSupplier the function which fetches or computes the user object * @return the builder itself for fluent method calls */ public Builder withUserSupplier(Function userSupplier) { verifyState(); user.userSupplier = userSupplier; return this; } /** * Builds the user, with the previously given settings. * * @return the resulting user */ public UserInfo build() { UserInfo result = user; user = null; return result; } } protected UserInfo() { } /** * Returns the unique ID of the user. * * @return the unique ID of the user */ public String getUserId() { return userId; } /** * Returns the login or descriptive name of the user. * * @return the name of the user */ public String getUserName() { return username; } /** * The unique ID of the tenant. * * @return the unique ID the tenant the user belongs to */ @Nullable public String getTenantId() { return tenantId; } /** * The name of the tenant. * * @return the name of the tenant the user belongs to */ @Nullable public String getTenantName() { return tenantName; } /** * The language code of the user. * * @return the two-letter language code of the user */ public String getLang() { return lang; } /** * Determines if the user has the requested permissions * * @param permissions the permissions to check * @return true if the user has all the requested permissions, false otherwise */ public boolean hasPermissions(String... permissions) { for (String permission : permissions) { if (!hasPermission(permission)) { return false; } } return true; } /** * Determines if the user has the given permission. *

* Next to plain permission names, permissions can also negated using !permission and on top of that, * whole * logical expressions in DNF (disjuctive normal form)can be passed in. *

* Such a formula is a set of expressions where a , represents an or and a + represents an * and. An example would be "logged-in,important-customer+!locked". This would translate to "the user has * to be logged in or it has to be an important customer and not be locked". * * @param permission the permission to check * @return true if the user has the permission, false otherwise */ public boolean hasPermission(String permission) { if (Strings.isEmpty(permission)) { return true; } if (DISABLED.equals(permission)) { return false; } if (ENABLED.equals(permission)) { return true; } for (String orClause : permission.split(",")) { if (permissionsFullfilled(orClause)) { return true; } } return false; } protected boolean permissionsFullfilled(String permissions) { for (String permission : permissions.split("\\+")) { if (!permissionFullfilled(permission)) { return false; } } return true; } protected boolean permissionFullfilled(String permission) { if (permission.startsWith("!")) { return permissions == null || !permissions.contains(permission.substring(1)); } else { return permissions != null && permissions.contains(permission); } } /** * Asserts that the user has the given permission. *

* If the user does not have the given permission, an exception is thrown. * * @param permission the permission to check */ public void assertPermission(String permission) { if (!hasPermission(permission)) { throw Exceptions.createHandled() .withNLSKey("UserInfo.missingPermission") .set("permission", permission) .handle(); } } /** * Determines if the user is logged in. * * @return true if the user has the permission {@link #PERMISSION_LOGGED_IN}, false otherwise */ public boolean isLoggedIn() { return hasPermission(PERMISSION_LOGGED_IN); } /** * Fetches the underlying user object of the given type. * * @param clazz the excepted type of the user object * @param the excepted type of the user object * @return the underlying user object or null if no object is present or if it has a non matching type */ @SuppressWarnings("unchecked") @Nullable public T getUserObject(Class clazz) { if (userSupplier == null) { return null; } Object user = userSupplier.apply(this); if (user != null && clazz.isAssignableFrom(user.getClass())) { return (T) user; } return null; } @Override public boolean is(@Nonnull Class type) { Transformable userObject = getUserObject(Transformable.class); if (userObject != null) { return userObject.is(type); } return super.is(type); } @SuppressWarnings("unchecked") @Override public Optional tryAs(@Nonnull Class adapterType) { Transformable userObject = getUserObject(Transformable.class); if (userObject != null) { return userObject.tryAs(adapterType); } return super.tryAs(adapterType); } /** * Returns a set of all permissions granted to the user. * * @return all permissions granted to the user. */ public Set getPermissions() { return Collections.unmodifiableSet(permissions); } /** * Obtains the user specific config. *

* This can be used to make parts of the system behave specific to the current scope, current tenant and user. * * @return the config object which contains all settings of the current scope, current tenant and user. */ public UserSettings getSettings() { if (settingsSupplier == null) { return UserContext.getCurrentScope().getSettings(); } else { return settingsSupplier.apply(this); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy