예제 #1
0
  private Message handleSecurityMessage(CommandMessage message) {
    GraniteConfig config = GraniteContext.getCurrentInstance().getGraniteConfig();

    Message response = null;

    if (!config.hasSecurityService())
      log.warn(
          "Ignored security operation (no security settings in granite-config.xml): %s", message);
    else if (!config.getSecurityService().acceptsContext())
      log.info(
          "Ignored security operation (security service does not handle this kind of granite context)",
          message);
    else {
      SecurityService securityService = config.getSecurityService();
      try {
        if (message.isLoginOperation())
          securityService.login(
              message.getBody(), (String) message.getHeader(Message.CREDENTIALS_CHARSET_HEADER));
        else securityService.logout();
      } catch (Exception e) {
        if (e instanceof SecurityServiceException)
          log.debug(e, "Could not process security operation: %s", message);
        else log.error(e, "Could not process security operation: %s", message);
        response = new ErrorMessage(message, e, true);
      }
    }

    if (response == null) {
      response = new AcknowledgeMessage(message, true);
      // For SDK 2.0.1_Hotfix2.
      if (message.isSecurityOperation()) response.setBody("success");
    }

    return response;
  }
예제 #2
0
  private Message handleDisconnectMessage(
      final ChannelFactory<?> channelFactory, CommandMessage message) {
    Channel client = getChannel(channelFactory, (String) message.getClientId());
    if (client == null) return handleUnknownClientMessage(message);

    removeChannel(client.getId(), false);

    AcknowledgeMessage reply = new AcknowledgeMessage(message);
    reply.setDestination(message.getDestination());
    reply.setClientId(client.getId());
    return reply;
  }
예제 #3
0
  private CommandMessage createLoginCommandMessage() {
    CommandMessage commandMessage = new CommandMessage();
    commandMessage.setOperation(CommandMessage.LOGIN_OPERATION);

    String credString = username + ":" + password;
    Encoder encoder = new Encoder(credString.length());
    encoder.encode(credString.getBytes());

    commandMessage.setBody(encoder.drain());
    commandMessage.setDestination(DESTINATION);
    return commandMessage;
  }
예제 #4
0
  private Message handleConnectMessage(
      final ChannelFactory<?> channelFactory, CommandMessage message) {
    Channel client = getChannel(channelFactory, (String) message.getClientId());

    if (client == null) return handleUnknownClientMessage(message);

    return null;
  }
예제 #5
0
  private Message handlePingMessage(ChannelFactory<?> channelFactory, CommandMessage message) {

    Channel channel = createChannel(channelFactory, (String) message.getClientId());

    AsyncMessage reply = new AcknowledgeMessage(message);
    reply.setClientId(channel.getId());
    Map<String, Object> advice = new HashMap<String, Object>();
    advice.put(RECONNECT_INTERVAL_MS_KEY, Long.valueOf(gravityConfig.getReconnectIntervalMillis()));
    advice.put(RECONNECT_MAX_ATTEMPTS_KEY, Long.valueOf(gravityConfig.getReconnectMaxAttempts()));
    advice.put(ENCODE_MESSAGE_BODY_KEY, Boolean.valueOf(gravityConfig.isEncodeMessageBody()));
    reply.setBody(advice);
    reply.setDestination(message.getDestination());

    log.debug("handshake.handle: reply=%s", reply);

    return reply;
  }
예제 #6
0
  private Message handleUnsubscribeMessage(
      final ChannelFactory<?> channelFactory, CommandMessage message) {
    Channel channel = getChannel(channelFactory, (String) message.getClientId());
    if (channel == null) return handleUnknownClientMessage(message);

    AsyncMessage reply = null;

    ServiceAdapter adapter = adapterFactory.getServiceAdapter(message);

    reply = (AcknowledgeMessage) adapter.manage(channel, message);

    postManage(channel);

    if (!(reply instanceof ErrorMessage)) {
      // Remove subscription message in distributed data (clustering).
      try {
        DistributedData gdd = graniteConfig.getDistributedDataFactory().getInstance();
        if (gdd != null) {
          String subscriptionId =
              (String) message.getHeader(AsyncMessage.DESTINATION_CLIENT_ID_HEADER);
          log.debug(
              "Removing subscription message from channel info: %s - %s",
              channel.getId(), subscriptionId);
          gdd.removeSubcription(channel.getId(), subscriptionId);
        }
      } catch (Exception e) {
        log.error(
            e,
            "Could not remove subscription from distributed data: %s - %s",
            channel.getId(),
            message.getHeader(AsyncMessage.DESTINATION_CLIENT_ID_HEADER));
      }
    }

    reply.setDestination(message.getDestination());
    reply.setClientId(channel.getId());
    reply.getHeaders().putAll(message.getHeaders());

    return reply;
  }
예제 #7
0
  private Message handleSubscribeMessage(
      final ChannelFactory<?> channelFactory,
      final CommandMessage message,
      final boolean saveMessageInSession) {

    final GraniteContext context = GraniteContext.getCurrentInstance();

    // Get and check destination.
    final Destination destination =
        context
            .getServicesConfig()
            .findDestinationById(message.getMessageRefType(), message.getDestination());

    if (destination == null) return getInvalidDestinationError(message);

    GravityInvocationContext invocationContext =
        new GravityInvocationContext(message, destination) {
          @Override
          public Object invoke() throws Exception {
            // Subscribe...
            Channel channel = getChannel(channelFactory, (String) message.getClientId());
            if (channel == null) return handleUnknownClientMessage(message);

            String subscriptionId =
                (String) message.getHeader(AsyncMessage.DESTINATION_CLIENT_ID_HEADER);
            if (subscriptionId == null) {
              subscriptionId = UUIDUtil.randomUUID();
              message.setHeader(AsyncMessage.DESTINATION_CLIENT_ID_HEADER, subscriptionId);
            }

            DistributedData gdd = graniteConfig.getDistributedDataFactory().getInstance();
            if (gdd != null) {
              if (!gdd.hasChannelId(channel.getId())) {
                gdd.addChannelId(
                    channel.getId(),
                    channel.getFactory().getClass().getName(),
                    context.getClientType());
                log.debug("Stored channel %s in distributed data", channel.getId());
              }

              if (Boolean.TRUE
                  .toString()
                  .equals(destination.getProperties().get("session-selector"))) {
                String selector = gdd.getDestinationSelector(destination.getId());
                log.debug("Session selector found: %s", selector);
                if (selector != null) message.setHeader(CommandMessage.SELECTOR_HEADER, selector);
              }
            }

            ServiceAdapter adapter = adapterFactory.getServiceAdapter(message);

            AsyncMessage reply = (AsyncMessage) adapter.manage(channel, message);

            postManage(channel);

            if (saveMessageInSession && !(reply instanceof ErrorMessage)) {
              // Save subscription message in distributed data (clustering).
              try {
                if (gdd != null) {
                  log.debug(
                      "Saving new subscription message for channel: %s - %s",
                      channel.getId(), message);
                  gdd.addSubcription(channel.getId(), message);
                }
              } catch (Exception e) {
                log.error(
                    e,
                    "Could not add subscription in distributed data: %s - %s",
                    channel.getId(),
                    subscriptionId);
              }
            }

            reply.setDestination(message.getDestination());
            reply.setClientId(channel.getId());
            reply.getHeaders().putAll(message.getHeaders());

            if (gdd != null && message.getDestination() != null) {
              gdd.setDestinationClientId(message.getDestination(), channel.getId());
              gdd.setDestinationSubscriptionId(message.getDestination(), subscriptionId);
            }

            return reply;
          }
        };

    // Check security 1 (destination).
    if (destination.getSecurizer() instanceof GravityDestinationSecurizer) {
      try {
        ((GravityDestinationSecurizer) destination.getSecurizer()).canSubscribe(invocationContext);
      } catch (Exception e) {
        return new ErrorMessage(message, e);
      }
    }

    // Check security 2 (security service).
    GraniteConfig config = context.getGraniteConfig();
    try {
      if (config.hasSecurityService() && config.getSecurityService().acceptsContext())
        return (Message) config.getSecurityService().authorize(invocationContext);

      return (Message) invocationContext.invoke();
    } catch (Exception e) {
      return new ErrorMessage(message, e, true);
    }
  }
예제 #8
0
  public Message handleMessage(
      final ChannelFactory<?> channelFactory, final Message message, boolean skipInterceptor) {

    AMF3MessageInterceptor interceptor = null;
    if (!skipInterceptor)
      interceptor =
          GraniteContext.getCurrentInstance().getGraniteConfig().getAmf3MessageInterceptor();

    Message reply = null;
    boolean publish = false;

    try {
      if (interceptor != null) interceptor.before(message);

      if (message instanceof CommandMessage) {
        CommandMessage command = (CommandMessage) message;

        switch (command.getOperation()) {
          case CommandMessage.LOGIN_OPERATION:
          case CommandMessage.LOGOUT_OPERATION:
            return handleSecurityMessage(command);

          case CommandMessage.CLIENT_PING_OPERATION:
            return handlePingMessage(channelFactory, command);
          case CommandMessage.CONNECT_OPERATION:
            return handleConnectMessage(channelFactory, command);
          case CommandMessage.DISCONNECT_OPERATION:
            return handleDisconnectMessage(channelFactory, command);
          case CommandMessage.SUBSCRIBE_OPERATION:
            return handleSubscribeMessage(channelFactory, command);
          case CommandMessage.UNSUBSCRIBE_OPERATION:
            return handleUnsubscribeMessage(channelFactory, command);

          default:
            throw new UnsupportedOperationException("Unsupported command operation: " + command);
        }
      }

      reply = handlePublishMessage(channelFactory, (AsyncMessage) message);
      publish = true;
    } finally {
      if (interceptor != null) interceptor.after(message, reply);
    }

    if (reply != null) {
      GraniteContext context = GraniteContext.getCurrentInstance();
      if (context.getSessionId() != null) {
        reply.setHeader("org.granite.sessionId", context.getSessionId());
        if (publish
            && context instanceof ServletGraniteContext
            && ((ServletGraniteContext) context).getSession(false) != null) {
          long serverTime = new Date().getTime();
          ((ServletGraniteContext) context)
              .getSession()
              .setAttribute(GraniteContext.SESSION_LAST_ACCESSED_TIME_KEY, serverTime);
          reply.setHeader("org.granite.time", serverTime);
          reply.setHeader(
              "org.granite.sessionExp",
              ((ServletGraniteContext) context).getSession().getMaxInactiveInterval());
        }
      }
    }

    return reply;
  }
예제 #9
0
 private static CommandMessage createLogoutCommandMessage() {
   CommandMessage commandMessage = new CommandMessage();
   commandMessage.setOperation(CommandMessage.LOGOUT_OPERATION);
   commandMessage.setDestination(DESTINATION);
   return commandMessage;
 }
예제 #10
0
  /**
   * Processes subscription related <code>CommandMessage</code>s. Subclasses that perform additional
   * custom subscription management should invoke <code>super.manageSubscriptions()</code> if they
   * choose to override this method.
   *
   * @param command The <code>CommandMessage</code> to process.
   */
  protected Message manageSubscriptions(CommandMessage command) {
    Message replyMessage = null;

    MessageDestination destination = (MessageDestination) getDestination(command);
    SubscriptionManager subscriptionManager = destination.getSubscriptionManager();

    Object clientId = command.getClientId();
    String endpointId = (String) command.getHeader(Message.ENDPOINT_HEADER);

    String subtopicString = (String) command.getHeader(AsyncMessage.SUBTOPIC_HEADER_NAME);

    ServiceAdapter adapter = destination.getAdapter();

    if (command.getOperation() == CommandMessage.SUBSCRIBE_OPERATION) {
      String selectorExpr = (String) command.getHeader(CommandMessage.SELECTOR_HEADER);

      getMessageBroker().inspectChannel(command, destination);

      // Give MessagingAdapter a chance to block the subscribe.
      if ((adapter instanceof MessagingAdapter)) {
        MessagingSecurityConstraintManager manager =
            ((MessagingAdapter) adapter).getSecurityConstraintManager();
        if (manager != null) manager.assertSubscribeAuthorization();
      }

      try {
        /*
         * This allows parallel add/remove subscribe calls (protected by the
         * concurrent hash table) but prevents us from doing any table mods
         * when the getSubscriptionState method is active
         */
        subscribeLock.readLock().lock();

        if (adapter.handlesSubscriptions()) {
          replyMessage = (Message) adapter.manage(command);
        } else {
          testSelector(selectorExpr, command);
        }
        /*
         * Even if the adapter is managing the subscription, we still need to
         * register this with the subscription manager so that we can match the
         * endpoint with the clientId.  I am not sure I like this though because
         * now the subscription is registered both with the adapter and with our
         * system so keeping them in sync is potentially problematic.   Also, it
         * seems like the adapter should have the option to manage endpoints themselves?
         */

        // Extract the maxFrequency that might have been specified by the client.
        int maxFrequency = processMaxFrequencyHeader(command);
        subscriptionManager.addSubscriber(
            clientId, selectorExpr, subtopicString, endpointId, maxFrequency);
      } finally {
        subscribeLock.readLock().unlock();
      }

      if (replyMessage == null) replyMessage = new AcknowledgeMessage();
    } else if (command.getOperation() == CommandMessage.UNSUBSCRIBE_OPERATION) {
      // Give MessagingAdapter a chance to block the unsubscribe, as long as
      // the subscription has not been invalidated.
      if ((adapter instanceof MessagingAdapter)
          && command.getHeader(CommandMessage.SUBSCRIPTION_INVALIDATED_HEADER) == null) {
        MessagingSecurityConstraintManager manager =
            ((MessagingAdapter) adapter).getSecurityConstraintManager();
        if (manager != null) manager.assertSubscribeAuthorization();
      }

      String selectorExpr = (String) command.getHeader(CommandMessage.SELECTOR_HEADER);

      try {
        subscribeLock.readLock().lock();

        if (adapter.handlesSubscriptions()) {
          replyMessage = (Message) adapter.manage(command);
        }
        subscriptionManager.removeSubscriber(clientId, selectorExpr, subtopicString, endpointId);
      } finally {
        subscribeLock.readLock().unlock();
      }

      if (replyMessage == null) replyMessage = new AcknowledgeMessage();
    } else if (command.getOperation() == CommandMessage.MULTI_SUBSCRIBE_OPERATION) {
      getMessageBroker().inspectChannel(command, destination);

      // Give MessagingAdapter a chance to block the multi subscribe.
      if ((adapter instanceof MessagingAdapter)) {
        MessagingSecurityConstraintManager manager =
            ((MessagingAdapter) adapter).getSecurityConstraintManager();
        if (manager != null) manager.assertSubscribeAuthorization();
      }

      try {
        /*
         * This allows parallel add/remove subscribe calls (protected by the
         * concurrent hash table) but prevents us from doing any table mods
         * when the getSubscriptionState method is active
         */
        subscribeLock.readLock().lock();

        if (adapter.handlesSubscriptions()) {
          replyMessage = (Message) adapter.manage(command);
        }

        // Deals with legacy collection setting
        Object[] adds =
            getObjectArrayFromHeader(command.getHeader(CommandMessage.ADD_SUBSCRIPTIONS));
        Object[] rems =
            getObjectArrayFromHeader(command.getHeader(CommandMessage.REMOVE_SUBSCRIPTIONS));

        if (adds != null) {
          // Extract the maxFrequency that might have been specified
          // by the client for every subscription (selector/subtopic).
          int maxFrequency = processMaxFrequencyHeader(command);
          for (int i = 0; i < adds.length; i++) {
            // Use the maxFrequency by default.
            int maxFrequencyPerSubscription = maxFrequency;
            String ss = (String) adds[i];
            int ix = ss.indexOf(CommandMessage.SUBTOPIC_SEPARATOR);
            if (ix != -1) {
              String subtopic = (ix == 0 ? null : ss.substring(0, ix));
              String selector = null;
              String selectorAndMaxFrequency =
                  ss.substring(ix + CommandMessage.SUBTOPIC_SEPARATOR.length());
              if (selectorAndMaxFrequency.length() != 0) {
                int ix2 = selectorAndMaxFrequency.indexOf(CommandMessage.SUBTOPIC_SEPARATOR);
                if (ix2 != -1) {
                  selector = (ix2 == 0 ? null : selectorAndMaxFrequency.substring(0, ix2));
                  String maxFrequencyString =
                      selectorAndMaxFrequency.substring(
                          ix2 + CommandMessage.SUBTOPIC_SEPARATOR.length());
                  if (maxFrequencyString.length() != 0) {
                    // Choose the minimum of Consumer level maxFrequency and subscription level
                    // maxFrequency.
                    int maxFrequencyCandidate = Integer.parseInt(maxFrequencyString);
                    maxFrequencyPerSubscription =
                        maxFrequencyPerSubscription == 0
                            ? maxFrequencyCandidate
                            : Math.min(maxFrequencyPerSubscription, maxFrequencyCandidate);
                  }
                }
              }
              subscriptionManager.addSubscriber(
                  clientId, selector, subtopic, endpointId, maxFrequencyPerSubscription);
            }
            // invalid message
          }
        }

        if (rems != null) {
          for (int i = 0; i < rems.length; i++) {
            String ss = (String) rems[i];
            int ix = ss.indexOf(CommandMessage.SUBTOPIC_SEPARATOR);
            if (ix != -1) {
              String subtopic = (ix == 0 ? null : ss.substring(0, ix));
              String selector = null;
              String selectorAndMaxFrequency =
                  ss.substring(ix + CommandMessage.SUBTOPIC_SEPARATOR.length());
              if (selectorAndMaxFrequency.length() != 0) {
                int ix2 = selectorAndMaxFrequency.indexOf(CommandMessage.SUBTOPIC_SEPARATOR);
                if (ix2 != -1)
                  selector = ix2 == 0 ? null : selectorAndMaxFrequency.substring(0, ix2);
              }
              subscriptionManager.removeSubscriber(clientId, selector, subtopic, endpointId);
            }
          }
        }
      } finally {
        subscribeLock.readLock().unlock();
      }

      if (replyMessage == null) replyMessage = new AcknowledgeMessage();
    } else if (command.getOperation() == CommandMessage.POLL_OPERATION) {
      // This code path handles poll messages sent by Consumer.receive().
      // This API should not trigger server side waits, so we invoke poll
      // and if there are no queued messages for this Consumer instance we
      // return an empty acknowledgement immediately.
      MessageClient client = null;
      try {
        client = subscriptionManager.getMessageClient(clientId, endpointId);

        if (client != null) {
          if (adapter.handlesSubscriptions()) {
            List missedMessages = (List) adapter.manage(command);
            if (missedMessages != null && !missedMessages.isEmpty()) {
              MessageBroker broker = getMessageBroker();
              for (Iterator iter = missedMessages.iterator(); iter.hasNext(); )
                broker.routeMessageToMessageClient((Message) iter.next(), client);
            }
          }
          FlushResult flushResult = client.getFlexClient().poll(client);
          List messagesToReturn = (flushResult != null) ? flushResult.getMessages() : null;
          if (messagesToReturn != null && !messagesToReturn.isEmpty()) {
            replyMessage = new CommandMessage(CommandMessage.CLIENT_SYNC_OPERATION);
            replyMessage.setBody(messagesToReturn.toArray());
          } else {
            replyMessage = new AcknowledgeMessage();
          }
          // Adaptive poll wait is never used in responses to Consumer.receive() calls.
        } else {
          ServiceException se = new ServiceException();
          se.setCode(NOT_SUBSCRIBED_CODE);
          se.setMessage(NOT_SUBSCRIBED, new Object[] {destination.getId()});
          throw se;
        }
      } finally {
        subscriptionManager.releaseMessageClient(client);
      }
    } else {
      ServiceException se = new ServiceException();
      se.setMessage(UNKNOWN_COMMAND, new Object[] {new Integer(command.getOperation())});
      throw se;
    }

    return replyMessage;
  }
예제 #11
0
 private int processMaxFrequencyHeader(CommandMessage command) {
   Object maxFrequencyHeader = command.getHeader(CommandMessage.MAX_FREQUENCY_HEADER);
   if (maxFrequencyHeader != null) return ((Integer) maxFrequencyHeader).intValue();
   return 0;
 }