From: Karsten Wutzke on
Hello!

Before anyone complains, this is basically a multipost from the
mainstream Java NG's. I couldn't get any/the answers I need, so I must
go to (what is for me) the "OO-design experts group". ;-)

I have a (Java) interface "Chat":

public interface Chat
{
public String getName();
public void setName(String strName); //basically not executable by
everyone

public User getOwner();
public void setOwner(User usrOwner); //basically not executable
by everyone

public List<User> getUserList();

//... which methods?
//join(User usr)
//sendMessage(User usr, Message msg)
//kick(User usr, User usrKicker)
//ban(User usr, usrBanner)
//unban(User usr, usrUnbanner)
//leave(User usr)
//...

}

How do you restrict access for a real chat room on the network by
using the current (or another user's) level/permissions (there are
admins, mods, owners, ops, normal users)?

1. The easiest way is probably not to expose functionality via the
GUI, so users with admin level will see a popup with more entries than
a regular chatter. However this is no real security concept. Accessing
the model objects can still produce an unwanted command (e.g. by some
artificial instance not having a GUI at all).

2. The list of commands generated via some CommandFactory (the objects
that would do something when a button gets pressed) is limited by the
user's (or some other) level. A normal user can't instantiate a
"BanCommand" for example. The command objects act as messenger
objects, but nevertheless those objects would still call the public
unfiltered methods on that interface.

3. Somehow provide different implementations of that interface by
subclassing (or else) and throwing some exception for those operations/
method calls that are not allowed with the current user's level. A
normal user calling myChat.ban(otherUser) would get such an exception.
Disadvantage of subclassing here would be, that I'd need one subclass
per user level (admin, moderator, owner, operator, normal). In case
the user's level gets upgraded, the instance/s of such chats would
have to be replaced. Looks like bad design to me.

Instead of subclassing one could also implement this via several
Strategies, one per method. I believe the "Bridge" pattern could be
applied as well, for dynamic method implementations.

In any way, I started creating a concrete subclass of a Chat interface
called "ChatProxy" which is supposed to
handle the communication with the actual chat server (no
implementation yet). Maybe that is supposed to be the class where the
restrictions belong. Such a proxy might act as an "access proxy" but
also as a "remote proxy".

I could need some more input on this matter designwise. Currently I
have the above Chat interface and two subclasses:

public abstract class ChatImpl implements Chat (needed at all???
what does it implement anyway??)
....

and

public class ChatProxy implements Chat
{
private final ChatImpl ci; //references above class

//^^dump the reference and concrete class at all, connecting to
the server directly?

//...implement the methods here, depending on the current user's
level

}

This is the naive approach of the GoF Proxy pattern that I started
with. I'm not quite sure if I need the ChatImpl class at all or
whether the proxy will connect to the server directly. (?)

Be aware that it is a requirement to upgrade user levels on the fly,
so having a ProxyFactory with different Chat(Proxy) implementations
per user level (admin, mod, owner, op, normal) might not be the right
thing.

I'm really out of ideas what could be the right way to do it, though
restricting functionality on (dynamic) user levels seems quite common
to me. This is why I hope to get some more insight from you, even if
you only left some comments "you're basically on the right way", "it's
probably better to do this", "forget that"...

Any help is greatly appreciated!

Karsten

PS: Which instance is supposed to handle the authentication stuff
anyway? The Proxy itself? Another "connection" object?

From: H. S. Lahman on
Responding to Wutzke...

> <snip example>
>
> How do you restrict access for a real chat room on the network by
> using the current (or another user's) level/permissions (there are
> admins, mods, owners, ops, normal users)?
>
> 1. The easiest way is probably not to expose functionality via the
> GUI, so users with admin level will see a popup with more entries than
> a regular chatter. However this is no real security concept. Accessing
> the model objects can still produce an unwanted command (e.g. by some
> artificial instance not having a GUI at all).

I don't buy this argument, at least directly. The subsystem or layer
where this object exists will have an interface for communicating with
the outside world that will be shared by all "users", whether they be a
person at a GUI or another chunk of software. That interface will have a
DbC precondition to ensure that the external context for invoking that
interface element is valid. IOW, it is not this subsystem's
responsibility to check if its clients are doing their jobs correctly.

OTOH, prudence suggests that software should be able to detect when it
is broken and cannot continue processing properly. So it is valid for
the subsystem to have correctness assertions that can detect if the
client has lost its mind and signal an exception if it has. So...

>
> 2. The list of commands generated via some CommandFactory (the objects
> that would do something when a button gets pressed) is limited by the
> user's (or some other) level. A normal user can't instantiate a
> "BanCommand" for example. The command objects act as messenger
> objects, but nevertheless those objects would still call the public
> unfiltered methods on that interface.

You could use the Command pattern to check privileges, but that is a
pretty complicated way to do a simple task.

> 3. Somehow provide different implementations of that interface by
> subclassing (or else) and throwing some exception for those operations/
> method calls that are not allowed with the current user's level. A
> normal user calling myChat.ban(otherUser) would get such an exception.
> Disadvantage of subclassing here would be, that I'd need one subclass
> per user level (admin, moderator, owner, operator, normal). In case
> the user's level gets upgraded, the instance/s of such chats would
> have to be replaced. Looks like bad design to me.

This is close but a better idea is to provide different interfaces to
the object and only expose the less privileged clients to the interface
elements they have a right to access. That, though, becomes difficult
when the client is external to the subsystem, like a GUI. One would need
to provide the right subsystem interface to the client, but which one is
right will depend on who is logged in.

The simplest way is to allow each user to identify themselves and
provide a privilege bitmap for each user from a separate <secure>
configuration source. There are many ways to do that, so the following
is only one possibility:

* creates R1 1
[UserSurrogate] ---------------- [UserFactory]
+ privilegeBitmap
| *
| accessed by
|
| R2
|
| *
[Chat]
+ getName()
+ setName()
+ getOwner()
+ setOwnder().

When a UserSurrogate is instantiated by the factory object (presumably
when someone logs into a chat session), the factory object goes to a DB
and looks up the privilegeBitmap for that particular user identifier to
initialize it. For accessors like getName and getOwner the privilege
doesn't matter so they don't do anything special. However, the setName
and setOwner accessors will access the privilegeBitmap and check if
their bit in it is set of not. If not, they generate and exception.

So what's wrong with this picture? The R2 relationship is *:*, so how
does a Chat know which UserSurrogate to access to get the bitmap? The
obvious and simplest way is for UserSurrogate to pass its bitmap value
in the message that it sends to Chat (e.g., setName(name, bitmap)). Note
that passing the bitmap is fine because that is under the control of the
subsystem in hand and it forces the mapping of privileges to Just Work
because it controls the initialization of privilegeBitmap.

[Caveat: passing the bitmap value is not the most robust solution from a
maintenance viewpoint, but I wanted to keep the example simple.]

>
> Instead of subclassing one could also implement this via several
> Strategies, one per method. I believe the "Bridge" pattern could be
> applied as well, for dynamic method implementations.
>
> In any way, I started creating a concrete subclass of a Chat interface
> called "ChatProxy" which is supposed to
> handle the communication with the actual chat server (no
> implementation yet). Maybe that is supposed to be the class where the
> restrictions belong. Such a proxy might act as an "access proxy" but
> also as a "remote proxy".

Note that UserSurrogate is essentially a proxy for the external user. It
is just less complicated than the GoF pattern because there is no exotic
dynamic substitution required here. When a message comes from GUI (or
whatever) is will contain an identifier for the actual user. The
subsystem interface will then redirect that message to the right
UserSurrogate object who will then talk to other objects as needed.


*************
There is nothing wrong with me that could
not be cured by a capful of Drano.

H. S. Lahman
hsl(a)pathfindermda.com
Pathfinder Solutions
http://www.pathfindermda.com
blog: http://pathfinderpeople.blogs.com/hslahman
"Model-Based Translation: The Next Step in Agile Development". Email
info(a)pathfindermda.com for your copy.
Pathfinder is hiring:
http://www.pathfindermda.com/about_us/careers_pos3.php.
(888)OOA-PATH



From: Daniel T. on
Karsten Wutzke <kwutzke(a)web.de> wrote:

> Before anyone complains, this is basically a multipost from the
> mainstream Java NG's. I couldn't get any/the answers I need, so I must
> go to (what is for me) the "OO-design experts group". ;-)
>
> I have a (Java) interface "Chat":
>
> public interface Chat
> {
> public String getName();
> public void setName(String strName); //basically not executable by
> everyone
>
> public User getOwner();
> public void setOwner(User usrOwner); //basically not executable
> by everyone
>
> public List<User> getUserList();
>
> //... which methods?
> //join(User usr)
> //sendMessage(User usr, Message msg)
> //kick(User usr, User usrKicker)
> //ban(User usr, usrBanner)
> //unban(User usr, usrUnbanner)
> //leave(User usr)
> //...
>
> }
>
> How do you restrict access for a real chat room on the network by
> using the current (or another user's) level/permissions (there are
> admins, mods, owners, ops, normal users)?

The question is the result of improperly thinking of the problem space.
Objects should not be sitting dormant waiting for a command to do a
particular task. Objects should know what they need to do, they are only
waiting for the information necessary to do it.

Think of a Printer for example. You don't order it to print, it lives to
print, all you need to do is tell it what to print.

> I'm really out of ideas what could be the right way to do it, though
> restricting functionality on (dynamic) user levels seems quite common
> to me. This is why I hope to get some more insight from you, even if
> you only left some comments "you're basically on the right way", "it's
> probably better to do this", "forget that"...
>
> Any help is greatly appreciated!

The metaphor I think of while reading your post is the human body,
trying to fight off pathogens while at the same time taking in foreign
matter. Your server seeks external input, is hungry for it, but it needs
to be able to detect valid/appropriate input from invalid input. A
multi-layerd approach would probably be necessary.

At the first layer, the input must be "digested", in converting the raw
data into useful objects, garbage must be detected and discarded, its
source identified and cut off. If you get garbage data from a particular
MAC address, you know not to eat anymore of that address' data.

The next layer would be to examine the data for how common it is. If the
server receives a Ban command from a source that routinely produces
them, then all is probably well. A bunch of Ban commands for an unknown
source is suspect.

Another layer would work independently from the above. It would look for
damage to the data in the system and work to repair that damage. Are the
number of banned users suddenly increasing? This layer would notify you
of the anomaly start unbanning users.

I've never written anything like what you are trying to create so all of
the above may be suspect. In general though, stop thinking of objects as
tools you use to achieve a particular end, and start giving them a
life/purpose of their own.
From: Karsten Wutzke on
On 17 Aug., 17:44, "H. S. Lahman" <h.lah...(a)verizon.net> wrote:
> Responding to Wutzke...
>
> > <snip example>
>
> > How do you restrict access for a real chat room on the network by
> > using the current (or another user's) level/permissions (there are
> > admins, mods, owners, ops, normal users)?
>
> > 1. The easiest way is probably not to expose functionality via the
> > GUI, so users with admin level will see a popup with more entries than
> > a regular chatter. However this is no real security concept. Accessing
> > the model objects can still produce an unwanted command (e.g. by some
> > artificial instance not having a GUI at all).
>
> I don't buy this argument, at least directly. The subsystem or layer
> where this object exists will have an interface for communicating with
> the outside world that will be shared by all "users", whether they be a
> person at a GUI or another chunk of software. That interface will have a
> DbC precondition to ensure that the external context for invoking that
> interface element is valid. IOW, it is not this subsystem's
> responsibility to check if its clients are doing their jobs correctly.
>
> OTOH, prudence suggests that software should be able to detect when it
> is broken and cannot continue processing properly. So it is valid for
> the subsystem to have correctness assertions that can detect if the
> client has lost its mind and signal an exception if it has. So...
>
>
>
> > 2. The list of commands generated via some CommandFactory (the objects
> > that would do something when a button gets pressed) is limited by the
> > user's (or some other) level. A normal user can't instantiate a
> > "BanCommand" for example. The command objects act as messenger
> > objects, but nevertheless those objects would still call the public
> > unfiltered methods on that interface.
>
> You could use the Command pattern to check privileges, but that is a
> pretty complicated way to do a simple task.

I wonder what you had in mind by saying complicated. The client knows
about the current user's access rights in a chat. This "access state"
is dynamic, that is it can change while chatting, e.g. when an
operator up- or degrades your level (admin, superop, owner, op,
tempop, normal). The state of the current users chat (one of many
active chats) can be set with something like setLevel(...). When that
is done, the chat will appear do be a little different, either some
functionality was added or some was removed.

What I had in mind then was to provide Commmand objects depending on
the user's level in the chat. These commands would be called from menu
items or buttons. If the level of a user doesn't allow a command, the
respective GUI component wouldn't be created (either Command object
creation throws an exception or null is returned).

This is not complicated IMHO, I just wonder why I'd need a Proxy then.
Maybe only a "remote proxy", but not "remote access/protection proxy"
since the access restriction was/is already handled by the command
factory (or such).


>
> > 3. Somehow provide different implementations of that interface by
> > subclassing (or else) and throwing some exception for those operations/
> > method calls that are not allowed with the current user's level. A
> > normal user calling myChat.ban(otherUser) would get such an exception.
> > Disadvantage of subclassing here would be, that I'd need one subclass
> > per user level (admin, moderator, owner, operator, normal). In case
> > the user's level gets upgraded, the instance/s of such chats would
> > have to be replaced. Looks like bad design to me.
>
> This is close but a better idea is to provide different interfaces to
> the object and only expose the less privileged clients to the interface
> elements they have a right to access. That, though, becomes difficult
> when the client is external to the subsystem, like a GUI. One would need
> to provide the right subsystem interface to the client, but which one is
> right will depend on who is logged in.
>

I have two problems with providing different interfaces to clients:

1. How does the client know which Proxy to expect/use? Isn't the
purpose of the Proxy to provide a placeholder so that clients *don't*
need to know which interface to expect? Furthermore, which variable
would I assign a concrete Proxy to after it got instantiated (via some
Factory maybe)?

Proxy classes are: AdminChatContext, SuperOpChatContext,
OwnerChatContext, OpChatContext, TempOpCHatContext, NormalChatContext.
Each class going from NormalChatContext up to AdminChatContext would
add 1-n new methods.

In the client of the proxy, what local variable would I assign the
concrete proxies to to make use of their extended interfaces?
Assigning them to the base

Chat cht = SomeFactory.createOpChatFactory();

seems right at first, but I can't access the concrete class' methods
without downcasting.


2. Isn't adding/withdrawing functionality dynamically rather a
decorator, providing different subclasses and methods? Even when using
decorators, clients are still left with problem 1.

My own summary would (currently) be:

Using subclassing for user rights not being able to use a common
interface to all seems not to be the right approach. Maybe I missed
something, so please correct me if I'm wrong.

> The simplest way is to allow each user to identify themselves and
> provide a privilege bitmap for each user from a separate <secure>
> configuration source. There are many ways to do that, so the following
> is only one possibility:
>
> * creates R1 1
> [UserSurrogate] ---------------- [UserFactory]
> + privilegeBitmap
> | *
> | accessed by
> |
> | R2
> |
> | *
> [Chat]
> + getName()
> + setName()
> + getOwner()
> + setOwnder().
>
> When a UserSurrogate is instantiated by the factory object (presumably
> when someone logs into a chat session), the factory object goes to a DB
> and looks up the privilegeBitmap for that particular user identifier to
> initialize it. For accessors like getName and getOwner the privilege
> doesn't matter so they don't do anything special. However, the setName
> and setOwner accessors will access the privilegeBitmap and check if
> their bit in it is set of not. If not, they generate and exception.
>

Right.

> So what's wrong with this picture? The R2 relationship is *:*, so how
> does a Chat know which UserSurrogate to access to get the bitmap? The
> obvious and simplest way is for UserSurrogate to pass its bitmap value
> in the message that it sends to Chat (e.g., setName(name, bitmap)). Note
> that passing the bitmap is fine because that is under the control of the
> subsystem in hand and it forces the mapping of privileges to Just Work
> because it controls the initialization of privilegeBitmap.
>
> [Caveat: passing the bitmap value is not the most robust solution from a
> maintenance viewpoint, but I wanted to keep the example simple.]
>

I understood that, ok. I must pass the user's level/permissions s/he
has for the chat (the State pattern variable) to the surrogate/proxy.

>
>
> > Instead of subclassing one could also implement this via several
> > Strategies, one per method. I believe the "Bridge" pattern could be
> > applied as well, for dynamic method implementations.
>
> > In any way, I started creating a concrete subclass of a Chat interface
> > called "ChatProxy" which is supposed to
> > handle the communication with the actual chat server (no
> > implementation yet). Maybe that is supposed to be the class where the
> > restrictions belong. Such a proxy might act as an "access proxy" but
> > also as a "remote proxy".
>
> Note that UserSurrogate is essentially a proxy for the external user. It
> is just less complicated than the GoF pattern because there is no exotic
> dynamic substitution required here.

Hmm I don't understand that really. Can you explain a little more what
you mean why there's no dynamic substitution here? The only thing that
changes (and must change) is the user's level *per chat*. So...

When a message comes from GUI (or
> whatever) is will contain an identifier for the actual user. The
> subsystem interface will then redirect that message to the right
> UserSurrogate object who will then talk to other objects as needed.
>

I wonder how it's possible to use concrete interfaces from the
client... Conceptually and practically I'm reverting to implementing a
*common* interface, that is, have n subclasses for the n possible user
levels/states. Methods not allowed for the chat's user level will
(probably) throw some exception. Like this a common interface can be
accessed and depending on the instance's class will do something
meaningful or report "invalid". When the user's chat level is changed,
the proxy instance provided will be different and consequently changes
what the user can do/access. The GUI will reflect this of course.

The command pattern also seems appropriate to use since I've written a
small framework which supports Command objects. I can also create
commands that are made up of several smaller commands. An example
would be a user to "Kick & ban" another user, effectively this could
be a KickCommmand + BanCommand.

Final note:

It took me quite a while to understand and learn more about the
problem/s at hand. I will probably do fine if I can get the few last
things straight in my head. I'd very much appreciate if you (or
others) could comment on my questions, even if it refers to only a
small part in the above.

TIA
Karsten

From: Karsten Wutzke on
On 17 Aug., 20:19, "Daniel T." <danie...(a)earthlink.net> wrote:
> Karsten Wutzke <kwut...(a)web.de> wrote:
> > Before anyone complains, this is basically a multipost from the
> > mainstream Java NG's. I couldn't get any/the answers I need, so I must
> > go to (what is for me) the "OO-design experts group". ;-)
>
> > I have a (Java) interface "Chat":
>
> > public interface Chat
> > {
> > public String getName();
> > public void setName(String strName); //basically not executable by
> > everyone
>
> > public User getOwner();
> > public void setOwner(User usrOwner); //basically not executable
> > by everyone
>
> > public List<User> getUserList();
>
> > //... which methods?
> > //join(User usr)
> > //sendMessage(User usr, Message msg)
> > //kick(User usr, User usrKicker)
> > //ban(User usr, usrBanner)
> > //unban(User usr, usrUnbanner)
> > //leave(User usr)
> > //...
>
> > }
>
> > How do you restrict access for a real chat room on the network by
> > using the current (or another user's) level/permissions (there are
> > admins, mods, owners, ops, normal users)?
>
> The question is the result of improperly thinking of the problem space.
> Objects should not be sitting dormant waiting for a command to do a
> particular task. Objects should know what they need to do, they are only
> waiting for the information necessary to do it.
>
> Think of a Printer for example. You don't order it to print, it lives to
> print, all you need to do is tell it what to print.
>
> > I'm really out of ideas what could be the right way to do it, though
> > restricting functionality on (dynamic) user levels seems quite common
> > to me. This is why I hope to get some more insight from you, even if
> > you only left some comments "you're basically on the right way", "it's
> > probably better to do this", "forget that"...
>
> > Any help is greatly appreciated!
>
> The metaphor I think of while reading your post is the human body,
> trying to fight off pathogens while at the same time taking in foreign
> matter. Your server seeks external input, is hungry for it, but it needs
> to be able to detect valid/appropriate input from invalid input. A
> multi-layerd approach would probably be necessary.
>
> At the first layer, the input must be "digested", in converting the raw
> data into useful objects, garbage must be detected and discarded, its
> source identified and cut off. If you get garbage data from a particular
> MAC address, you know not to eat anymore of that address' data.
>
> The next layer would be to examine the data for how common it is. If the
> server receives a Ban command from a source that routinely produces
> them, then all is probably well. A bunch of Ban commands for an unknown
> source is suspect.
>
> Another layer would work independently from the above. It would look for
> damage to the data in the system and work to repair that damage. Are the
> number of banned users suddenly increasing? This layer would notify you
> of the anomaly start unbanning users.
>
> I've never written anything like what you are trying to create so all of
> the above may be suspect. In general though, stop thinking of objects as
> tools you use to achieve a particular end, and start giving them a
> life/purpose of their own.

I'm not sure if we're talking about the same, but my OP was about the
client side of a chat app only. The server is already implemented (IRC
flavor).

Karsten