Skip to content

Commit 1c2d616

Browse files
committed
Merged branch '2.7.x' into 'master'.
2 parents ec8df47 + 2bfee7a commit 1c2d616

27 files changed

Lines changed: 1984 additions & 1066 deletions

File tree

cometd-java/bayeux-api/src/main/java/org/cometd/bayeux/ChannelId.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ public static boolean isMeta(String channelId)
343343

344344
/**
345345
* <p>Helper method to test if the string form of a {@code ChannelId}
346-
* represents a {@link #isService()} service} {@code ChannelId}.</p>
346+
* represents a {@link #isService() service} {@code ChannelId}.</p>
347347
*
348348
* @param channelId the channel id to test
349349
* @return whether the given channel id is a service channel id
@@ -355,7 +355,7 @@ public static boolean isService(String channelId)
355355

356356
/**
357357
* <p>Helper method to test if the string form of a {@code ChannelId}
358-
* represents a {@link #isBroadcast()} broadcast} {@code ChannelId}.</p>
358+
* represents a {@link #isBroadcast() broadcast} {@code ChannelId}.</p>
359359
*
360360
* @param channelId the channel id to test
361361
* @return whether the given channel id is a broadcast channel id

cometd-java/bayeux-api/src/main/java/org/cometd/bayeux/server/SecurityPolicy.java

Lines changed: 59 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,33 +16,35 @@
1616

1717
package org.cometd.bayeux.server;
1818

19+
import org.cometd.bayeux.Session;
20+
import org.cometd.bayeux.client.ClientSessionChannel;
21+
1922
/**
20-
* <p>A Bayeux {@link SecurityPolicy} defines the broad authorization constraints that must be enforced by
21-
* a {@link BayeuxServer}.
22-
* </p>
23-
* The usage of SecurityPolicy has been mostly replaced by the more flexible {@link Authorizer}.
24-
* ,p>
25-
* <p>A {@link BayeuxServer} may deny the handshake from clients that do not have proper
26-
* authentication credentials, or may deny clients to publish on reserved channels and so on;
27-
* all these activities are controlled by the {@link SecurityPolicy} implementation installed
28-
* on the {@link BayeuxServer}.
23+
* A {@link SecurityPolicy} defines the broad authorization constraints that must be
24+
* enforced by a {@link BayeuxServer}.
25+
* <p />
26+
* The usage of {@link SecurityPolicy} has been mostly replaced by the usage of the
27+
* more flexible {@link Authorizer} for creation of channels, subscription to channels
28+
* and publish to channels.
29+
* {@link SecurityPolicy} is still the central authorization component for handshakes.
30+
* <p />
31+
* A {@link BayeuxServer} may deny the handshake from clients that do not have
32+
* proper authentication credentials, or may deny clients to publish on reserved
33+
* channels and so on; all these activities are controlled by the {@link SecurityPolicy}
34+
* implementation installed on the {@link BayeuxServer} via
35+
* {@link BayeuxServer#setSecurityPolicy(SecurityPolicy)}.
36+
*
2937
* @see ServerChannel#addAuthorizer(Authorizer)
3038
*/
3139
public interface SecurityPolicy
3240
{
33-
/**
34-
* Checks if a message should be allowed to create a new channel.
35-
*
36-
* @param server the {@link BayeuxServer} object
37-
* @param session the client sending the message (may be null if an anonymous publish is attempted)
38-
* @param channelId the channel to be created
39-
* @param message the message trying to create the channel
40-
* @return true if the channel should be created
41-
*/
42-
boolean canCreate(BayeuxServer server, ServerSession session, String channelId, ServerMessage message);
43-
4441
/**
4542
* Checks if a handshake message should be accepted.
43+
* <p />
44+
* Both remote sessions and local sessions are subject to this check.
45+
* Applications usually want local sessions (that is, server-side only sessions related to services)
46+
* to always pass this check, so a typical implementation filters local session using
47+
* {@link ServerSession#isLocalSession()}.
4648
*
4749
* @param server the {@link BayeuxServer} object
4850
* @param session the session (not yet added to the BayeuxServer)
@@ -53,24 +55,53 @@ public interface SecurityPolicy
5355
boolean canHandshake(BayeuxServer server, ServerSession session, ServerMessage message);
5456

5557
/**
56-
* Checks if a client can publish a message to a channel.
58+
* Checks if a message should be allowed to create a new channel.
59+
* <p />
60+
* A subscribe message or publish message to a channel not yet known to the server triggers this check.
61+
* Both remote sessions and local sessions, when performing subscribes or publishes via
62+
* {@link ClientSessionChannel#subscribe(ClientSessionChannel.MessageListener)} or
63+
* {@link ClientSessionChannel#publish(Object)} are therefore subject to this check.
64+
* <p />
65+
* Direct calls to {@link BayeuxServer#createIfAbsent(String, ConfigurableServerChannel.Initializer...)}
66+
* are not subject to this check.
5767
*
5868
* @param server the {@link BayeuxServer} object
59-
* @param session the client sending the message (may be null if an anonymous publish is attempted).
60-
* @param channel the channel to publish to
61-
* @param message the message to being published
62-
* @return true if the client can publish to the channel
69+
* @param session the client sending the message
70+
* @param channelId the channel to be created
71+
* @param message the message trying to create the channel
72+
* @return true if the channel should be created
6373
*/
64-
boolean canPublish(BayeuxServer server, ServerSession session, ServerChannel channel, ServerMessage message);
74+
boolean canCreate(BayeuxServer server, ServerSession session, String channelId, ServerMessage message);
6575

6676
/**
67-
* Checks if a client is allowed to subscribe to a channel.
77+
* Checks if a subscribe message from a client is allowed to subscribe to a channel.
78+
* <p />
79+
* Both remote and local sessions are subject to this check when performing subscribes via
80+
* {@link ClientSessionChannel#subscribe(ClientSessionChannel.MessageListener)}.
81+
* <p />
82+
* {@link ServerChannel#subscribe(ServerSession)} is not subject to this check.
6883
*
6984
* @param server the {@link BayeuxServer} object
70-
* @param session the client sending the message (may be null if an anonymous subscribe is attempted).
85+
* @param session the client sending the message
7186
* @param channel the channel to subscribe to
7287
* @param message the subscribe message
7388
* @return true if the client can subscribe to the channel
7489
*/
7590
boolean canSubscribe(BayeuxServer server, ServerSession session, ServerChannel channel, ServerMessage message);
91+
92+
/**
93+
* Checks if a client can publish a message to a channel.
94+
* <p />
95+
* Both remote and local sessions are subject to this check when performing publishes via
96+
* {@link ClientSessionChannel#publish(Object)}.
97+
* <p />
98+
* {@link ServerChannel#publish(Session, Object, String)} is not subject to this check.
99+
*
100+
* @param server the {@link BayeuxServer} object
101+
* @param session the client sending the message
102+
* @param channel the channel to publish to
103+
* @param message the message to being published
104+
* @return true if the client can publish to the channel
105+
*/
106+
boolean canPublish(BayeuxServer server, ServerSession session, ServerChannel channel, ServerMessage message);
76107
}

cometd-java/cometd-java-annotations/src/main/java/org/cometd/annotation/ClientAnnotationProcessor.java

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.lang.reflect.Field;
2020
import java.lang.reflect.InvocationTargetException;
2121
import java.lang.reflect.Method;
22+
import java.lang.reflect.Modifier;
2223
import java.util.Arrays;
2324
import java.util.List;
2425
import java.util.concurrent.ConcurrentHashMap;
@@ -109,6 +110,9 @@ private boolean processCallbacks(Object bean)
109110
if (serviceAnnotation == null)
110111
return false;
111112

113+
if (!Modifier.isPublic(klass.getModifiers()))
114+
throw new IllegalArgumentException("Service class '" + klass.getName() + "' must be public");
115+
112116
boolean result = processListener(bean);
113117
result |= processSubscription(bean);
114118
return result;
@@ -218,6 +222,9 @@ private boolean processListener(Object bean)
218222
Listener listener = method.getAnnotation(Listener.class);
219223
if (listener != null)
220224
{
225+
if (!Modifier.isPublic(method.getModifiers()))
226+
throw new IllegalArgumentException("Service method '" + method.getName() + "' in class '" + method.getDeclaringClass().getName() + "' must be public");
227+
221228
String[] channels = listener.value();
222229
for (String channel : channels)
223230
{
@@ -272,6 +279,9 @@ private boolean processSubscription(Object bean)
272279
Subscription subscription = method.getAnnotation(Subscription.class);
273280
if (subscription != null)
274281
{
282+
if (!Modifier.isPublic(method.getModifiers()))
283+
throw new IllegalArgumentException("Service method '" + method.getName() + "' in class '" + method.getDeclaringClass().getName() + "' must be public");
284+
275285
String[] channels = subscription.value();
276286
for (String channel : channels)
277287
{
@@ -336,24 +346,23 @@ private ListenerCallback(Object target, Method method, String channel)
336346

337347
public void onMessage(ClientSessionChannel channel, Message message)
338348
{
339-
boolean accessible = method.isAccessible();
340349
try
341350
{
342-
method.setAccessible(true);
343351
method.invoke(target, message);
344352
}
345353
catch (InvocationTargetException x)
346354
{
347-
throw new RuntimeException(x.getCause());
355+
Throwable cause = x.getCause();
356+
if (cause instanceof RuntimeException)
357+
throw (RuntimeException)cause;
358+
if (cause instanceof Error)
359+
throw (Error)cause;
360+
throw new RuntimeException(cause);
348361
}
349362
catch (IllegalAccessException x)
350363
{
351364
throw new RuntimeException(x);
352365
}
353-
finally
354-
{
355-
method.setAccessible(accessible);
356-
}
357366
}
358367
}
359368

@@ -399,24 +408,23 @@ private void subscribe()
399408

400409
private void forward(Message message)
401410
{
402-
boolean accessible = method.isAccessible();
403411
try
404412
{
405-
method.setAccessible(true);
406413
method.invoke(target, message);
407414
}
408415
catch (InvocationTargetException x)
409416
{
410-
throw new RuntimeException(x.getCause());
417+
Throwable cause = x.getCause();
418+
if (cause instanceof RuntimeException)
419+
throw (RuntimeException)cause;
420+
if (cause instanceof Error)
421+
throw (Error)cause;
422+
throw new RuntimeException(cause);
411423
}
412424
catch (IllegalAccessException x)
413425
{
414426
throw new RuntimeException(x);
415427
}
416-
finally
417-
{
418-
method.setAccessible(accessible);
419-
}
420428
}
421429
}
422430
}

cometd-java/cometd-java-annotations/src/main/java/org/cometd/annotation/ServerAnnotationProcessor.java

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.lang.reflect.Field;
2020
import java.lang.reflect.InvocationTargetException;
2121
import java.lang.reflect.Method;
22+
import java.lang.reflect.Modifier;
2223
import java.util.ArrayList;
2324
import java.util.Arrays;
2425
import java.util.List;
@@ -242,6 +243,9 @@ public boolean processCallbacks(Object bean)
242243
if (serviceAnnotation == null)
243244
return false;
244245

246+
if (!Modifier.isPublic(klass.getModifiers()))
247+
throw new IllegalArgumentException("Service class '" + klass.getName() + "' must be public");
248+
245249
LocalSession session = findOrCreateLocalSession(bean, serviceAnnotation.value());
246250
boolean result = processListener(bean, session);
247251
result |= processSubscription(bean, session);
@@ -378,6 +382,9 @@ private boolean processListener(Object bean, LocalSession localSession)
378382
Listener listener = method.getAnnotation(Listener.class);
379383
if (listener != null)
380384
{
385+
if (!Modifier.isPublic(method.getModifiers()))
386+
throw new IllegalArgumentException("Service method '" + method.getName() + "' in class '" + method.getDeclaringClass().getName() + "' must be public");
387+
381388
String[] channels = listener.value();
382389
for (String channel : channels)
383390
{
@@ -433,6 +440,9 @@ private boolean processSubscription(Object bean, LocalSession localSession)
433440
Subscription subscription = method.getAnnotation(Subscription.class);
434441
if (subscription != null)
435442
{
443+
if (!Modifier.isPublic(method.getModifiers()))
444+
throw new IllegalArgumentException("Service method '" + method.getName() + "' in class '" + method.getDeclaringClass().getName() + "' must be public");
445+
436446
String[] channels = subscription.value();
437447
for (String channel : channels)
438448
{
@@ -498,25 +508,24 @@ public boolean onMessage(ServerSession from, ServerChannel channel, ServerMessag
498508
if (from == localSession.getServerSession() && !receiveOwnPublishes)
499509
return true;
500510

501-
boolean accessible = method.isAccessible();
502511
try
503512
{
504-
method.setAccessible(true);
505513
Object result = method.invoke(target, from, message);
506514
return !Boolean.FALSE.equals(result);
507515
}
508516
catch (InvocationTargetException x)
509517
{
510-
throw new RuntimeException(x.getCause());
518+
Throwable cause = x.getCause();
519+
if (cause instanceof RuntimeException)
520+
throw (RuntimeException)cause;
521+
if (cause instanceof Error)
522+
throw (Error)cause;
523+
throw new RuntimeException(cause);
511524
}
512525
catch (IllegalAccessException x)
513526
{
514527
throw new RuntimeException(x);
515528
}
516-
finally
517-
{
518-
method.setAccessible(accessible);
519-
}
520529
}
521530
}
522531

@@ -541,24 +550,23 @@ public SubscriptionCallback(LocalSession localSession, Object target, Method met
541550

542551
public void onMessage(ClientSessionChannel channel, Message message)
543552
{
544-
boolean accessible = method.isAccessible();
545553
try
546554
{
547-
method.setAccessible(true);
548555
method.invoke(target, message);
549556
}
550557
catch (InvocationTargetException x)
551558
{
552-
throw new RuntimeException(x.getCause());
559+
Throwable cause = x.getCause();
560+
if (cause instanceof RuntimeException)
561+
throw (RuntimeException)cause;
562+
if (cause instanceof Error)
563+
throw (Error)cause;
564+
throw new RuntimeException(cause);
553565
}
554566
catch (IllegalAccessException x)
555567
{
556568
throw new RuntimeException(x);
557569
}
558-
finally
559-
{
560-
method.setAccessible(accessible);
561-
}
562570
}
563571
}
564572
}

0 commit comments

Comments
 (0)