Konstantin,

Thank you for your prompt and helpful response... at least I know I haven't overlooked something simple. With your encouragement, I'm happy to keep "fighting the alligators until I can get back to draining the swamp"!

On 10/01/12 02:56, Konstantin Kolinko wrote:
2012/1/9 Brian Burch<br...@pingtoo.com>:
On 06/01/12 11:47, Konstantin Kolinko wrote:

2012/1/6 Brian Burch<br...@pingtoo.com>:

I am developing some new unit tests to validate SingleSignOn and
Authenticator logic. I have used this existing test class as my template:

org.apache.catalina.authenticator.TestDigestAuthenticator

.. which extends org.apache.catalina.startup.TomcatBaseTest.

I noticed that TestDigestAuthenticator sets up its own MapRealm and
assigns
it to its single Context. I thought this logic was unnecessary, and so my
own initial test logic simply used the default RealmBase provided by the
underlying Tomcat instance. I add my test user and role to that. It
worked
fine with my simple cases, however...

To test SSO, I need to set up two Contexts under the same Realm. I see
the
following message in the output log:

INFO: The start() method was called on component [Realm[Simple]] after
start() had already been called. The second call will be ignored.

I know it is an INFO message. I know the second start (and its associated
stop) are ignored and therefore are harmless. However, I am reluctant to
simply shrug and ignore it. My instincts tell me something isn't right.

I have done quite a lot of investigating, but the underlying logic is
very
hard for me to follow. Here is what I am sure about:

1. The message is ONLY emitted in tests that create two Contexts and each
have the same Realm assigned with setRealm.

2. The message is NOT emitted at the time the Contexts are created and
defined (servlets, security constraints, etc).

3. The message IS emitted after the Tomcat.start method is called.

4. The message is emitted by one of the two threads which are started on
behalf of my two contexts. The messages are issued by the start and stop
methods in the abstract class org.apache.catalina.util.LifecycleBase.

5. org.apache.catalina.realm.RealmBase extends
org.apache.catalina.util.LifecycleMBeanBase which extends LifecycleBase.

My currently unanswered questions are:

1. Is this message normal? (I don't see it when I start multiple contexts
under a real tomcat server, but perhaps the logging properties are
different).

2. Why isn't the redundant startup of the Realm detected earlier and
simply
avoided (maybe the Threads are intended to race to be first with startup
-
but then I think the message should be debug level and not sound so
scary).


Please don't waste your time investigating this for me. I am only asking
the
question because I don't want too get side-tracked if one of you already
knows the answers to my questions. I'd like to settle the matter quickly
and
get back to my original task!

Thanks for listening,


The message is expected. I would say that the configuration is wrong,
or at least unusual.

If you look at the default server.xml file you will note that the
<Realm>    element there belongs to Engine. That is why it is started
once.


I agree, and this is what the TomcatBaseTest expects. If you "tickle" tomcat
with TomcatBaseTest.getTomcatInstance() and then with
Tomcat.getDefaultRealm(), a new default RealBase (memory) instance is
definitely created.


When Contexts are created and their context.xml files are parsed, the
Contexts always get distinct new Realm instances.

Instead of assigning the same Realm instance to both Contexts you
should assign it to an upper container (I have not looked at the API
though).  Or maybe you can have different Realm instances, but which
connect to the same backing storage?


When the StandardEngine (extending ContainerBase) thread starts, I would
expect percolating getRealm calls (from Context to Host to Engine) to
eventually arrive at the already-defined Tomcat default Realm. HOWEVER,
StandardEngine overrides the ContainerBase.getRealm method and ensures that
an unconfigured JAAS Realm is instantiated as the default for the Context,
because it cannot locate its parent (the field is certainly null, not
tomcat), so it decides to use this JAAS as the backstop.

This looks to me as if some refactoring between tomcat 5 and 6 left the
Tomcat default memory realm orphaned from the StandardEngine, which now
operates independently and establishes a completely different default realm.
Perhaps the right hand no longer knows what the left hand is doing????

Funny thing is that I googled this:

http://tomcat.10.n6.nabble.com/default-realm-set-to-JAASRealm-in-StandardEngine-td2005479.html

... and your name (Konstantin) is all over it! Can you cast you mind back 4
months and try to give me a clue about the history of this change to the
logic?

My feeling is that we need to stop StandardEngine from unilaterally creating
an unconfigured JAAS default Realm... and help the poor thing find its true
parent, i.e. tomcat, which has a perfectly serviceable default memory realm
just waiting to be used!

Tomcat is not part of container hierarchy.
Tomcat class is just a wrapper/factory that helps to launch standalone
server instances. It is not used at all when you launch proper
standalone Tomcat server.

The hierarchy is what you see in server.xml starting with<Server>
(StandardServer).

(Well, truly speaking StandardServer is not a container, it does not
implement Contaner interface).

Also docs:
http://tomcat.apache.org/tomcat-7.0-doc/config/realm.html
- see where Realm has to be placed.

Yeah.. I've read that stuff forwards, backwards and sideways. I still don't feel completely confident relating what it says to what I see in the latest source, so please be patient if you think I'm asking about something that is already in the docs.

Regarding Tomcat class behaviour - I created issue in Bugzilla:
https://issues.apache.org/bugzilla/show_bug.cgi?id=52443

That WAS as surprise to me! Thanks - it confirms my suspicions, but I wasn't brave enough to call it a bug at this time.

Regarding your use case:
As of now I still think you should create two separate Realm for those
web applications. (Another way is to assign one realm to Engine, but
that does not play well with Tomcat#addWebapp(), as I mentioned in the
above issue).

At the moment I don't see it like that. I feel the Realm should be shared between the Contexts that use it - in my case, which seems to be realistic, that means all webapps use the same Realm.

Re: old thread
I still think that that behaviour is not very good. At least it is bad
that it is not documented. Anyway, some default Realm implementation
is needed,

Agreed. Even if that default Realm implementation is not properly configured, it makes sense to let tomcat start "securely" and log an error.

and I would prefer some other realm implementation as the
default.
But as I do not know any real problems with that JAASRealm, and I
there is no other ready-to-use implementation that can be used as a
replacement, the above alone is not enough to go with breaking the
current behaviour. I suspect that removing JAASRealm is risky and can
break some embedded Tomcat uses.

My main concern is the unit tests, but it should go without saying that I don't want to break a production system, even if we haven't yet got a unit test that locks in the existing (correct?) behaviour.

I wonder why the default was changed from MemoryRealm to JAASRealm? Was it because JAAS doesn't need any server.xml customisation - the config file is specified in the jvm startup options?

I have searched the latest source for uses of Tomcat.getDefaultRealm(), which instantiates the MemoryRealm in the case where a default realm has not yet been set. I find it is ONLY used in my new test classes in the org.apache.catalina.authenticator package. I haven't yet found a corresponding setdefaultRealm method in the class hierarchy, so at the moment I am assuming it doesn't exist.

That observation suggests to me the solution to my problem lies with making TomcatBasetest provide its default realm to StandardEngine, thus derailing instantiation of a default JAASRealm. If I can find a neat way to do this, then it will allow the unit tests to be elegant and minimalist, while leaving all production behaviour unchanged. I would prefer to do it programmatically, rather than build a server.xml for each unit test.

I'll look into this approach, bearing in mind that it might still lead me into trouble with Realm.start and stop problems down the track.

Brian

Best regards,
Konstantin Kolinko

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to