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

org.cometd.bayeux.server.Authorizer Maven / Gradle / Ivy

There is a newer version: 4.0.9
Show newest version
/*
 * Copyright (c) 2008-2020 the original author or authors.
 *
 * 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.cometd.bayeux.server;

import org.cometd.bayeux.Channel;
import org.cometd.bayeux.ChannelId;
import org.cometd.bayeux.Promise;

/**
 * 

{@link Authorizer}s authorize {@link Operation operations} on {@link ServerChannel channels}.

*

Authorizers can be {@link ConfigurableServerChannel#addAuthorizer(Authorizer) added to} and * {@link ConfigurableServerChannel#removeAuthorizer(Authorizer)} removed from} channels, even wildcard * channels.

*

{@link Authorizer}s work together with the {@link SecurityPolicy} to determine if a * {@link Operation#CREATE channel creation}, a {@link Operation#SUBSCRIBE channel subscribe} or a * {@link Operation#PUBLISH publish operation} may succeed. *

*

For an operation on a channel, the authorizers on the wildcard channels that match the channel and the * authorizers on the channel itself (together known at the authorizers set for that channel) will be * consulted to check if the the operation is granted, denied or ignored.

*

The list of wildcard channels that match the channel is obtained from {@link ChannelId#getWilds()}.

*

The following is the authorization algorithm:

*
    *
  • If there is a security policy, and the security policy denies the request, then the request is denied.
  • *
  • Otherwise, if the authorizers set is empty, the request is granted.
  • *
  • Otherwise, if no authorizer explicitly grants the operation, the request is denied.
  • *
  • Otherwise, if at least one authorizer explicitly grants the operation, and no authorizer explicitly denies the * operation, the request is granted.
  • *
  • Otherwise, if one authorizer explicitly denies the operation, remaining authorizers are not consulted, and the * request is denied.
  • *
*

The order in which the authorizers are checked is not important.

*

Typically, authorizers are setup during the configuration of a channel:

*
 * BayeuxServer bayeuxServer = ...;
 * bayeuxServer.createIfAbsent("/television/cnn", new ConfigurableServerChannel.Initializer()
 * {
 *     public void configureChannel(ConfigurableServerChannel channel)
 *     {
 *         // Grant subscribe to all
 *         channel.addAuthorizer(GrantAuthorizer.GRANT_SUBSCRIBE);
 *
 *         // Grant publishes only to CNN employees
 *         channel.addAuthorizer(new Authorizer()
 *         {
 *             public Result authorize(Operation operation, ChannelId channel,
 *                                     ServerSession session, ServerMessage message)
 *             {
 *                 if (operation == Operation.PUBLISH &&
 *                         session.getAttribute("isCNNEmployee") == Boolean.TRUE)
 *                     return Result.grant();
 *                 else
 *                     return Result.ignore();
 *             }
 *         });
 *     }
 * });
 * 
*

A typical usage of authorizers is as follows:

*
    *
  • Create a wildcard authorizer that matches all channels and neither grants or * denies (e.g. use {@code org.cometd.server.authorizer.GrantAuthorizer.GRANT_NONE}). * This authorizer can be added to channel /** or to a more specific channel for your application such as * /game/**. * This ensures that authorizers set is not empty and that another authorizer must explicitly grant access.
  • *
  • For public channels, that all users can access, add authorizers that will simply grant * publish and/or subscribe permissions to the specific or wildcard channels.
  • *
  • For access controlled channels (e.g. only nominated players can publish to a game channel), then * specific implementation of authorizers need to be created that will check identities and possibly other * state before granting permission. * Typically there is no need for such authorizers to explicitly deny access, unless that attempted access * represents a specific error condition that needs to be passed to the client in the message associated * with a deny.
  • *
  • For cross cutting concerns, such as checking a users credit or implementing user bans, authorizers * can be created to explicitly deny access, without the need to modify all authorizers already in place * that may grant.
  • *
* * @see SecurityPolicy */ public interface Authorizer { /** * Operations that are to be authorized on a channel */ enum Operation { /** * The operation to create a channel that does not exist */ CREATE, /** * The operation to subscribe to a channel to receive messages published to it */ SUBSCRIBE, /** * The operation to publish messages to a channel */ PUBLISH } /** *

Callback invoked to authorize the given {@code operation} on the given {@code channel}.

*

Additional parameters are passed to this method as context parameters, so that it is possible * to implement complex logic based on the {@link ServerSession} and {@link ServerMessage} that * are requesting the authorization.

*

Note that the message channel is not the same as the {@code channelId} parameter. For example, * for subscription requests, the message channel is {@link Channel#META_SUBSCRIBE}, while the * {@code channelId} parameter is the channel for which the subscription is requested.

*

Note that for {@link Operation#CREATE create operation}, the channel instance does not yet * exist: it will be created only after the authorization is granted.

* * @param operation the operation to authorize * @param channel the channel for which the authorization has been requested * @param session the session that is requesting the authorization * @param message the message that triggered the authorization request * @param promise the promise to notify of the authorization result */ default void authorize(Operation operation, ChannelId channel, ServerSession session, ServerMessage message, Promise promise) { promise.succeed(authorize(operation, channel, session, message)); } /** *

Blocking version of {@link #authorize(Operation, ChannelId, ServerSession, ServerMessage, Promise)}.

* * @param operation the operation to authorize * @param channel the channel for which the authorization has been requested * @param session the session that is requesting the authorization * @param message the message that triggered the authorization request * @return the authorization result */ Result authorize(Operation operation, ChannelId channel, ServerSession session, ServerMessage message); /** *

The result of an authentication request.

*/ public static abstract class Result { /** * @param reason the reason for which the authorization is denied * @return a result that denies the authorization */ public static Result deny(String reason) { return new Denied(reason); } /** * @return a result that grants the authorization */ public static Result grant() { return Granted.GRANTED; } /** * @return a result that ignores the authorization, leaving the decision to other {@link Authorizer}s. */ public static Result ignore() { return Ignored.IGNORED; } public boolean isDenied() { return false; } public boolean isGranted() { return false; } @Override public String toString() { return getClass().getSimpleName().toLowerCase(); } public static final class Denied extends Result { private final String reason; private Denied(String reason) { if (reason == null) { reason = ""; } this.reason = reason; } public String getReason() { return reason; } @Override public boolean isDenied() { return true; } @Override public String toString() { return super.toString() + " (reason='" + reason + "')"; } } public static final class Granted extends Result { private static final Granted GRANTED = new Granted(); private Granted() { } @Override public boolean isGranted() { return true; } } public static final class Ignored extends Result { private static final Ignored IGNORED = new Ignored(); private Ignored() { } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy