I figured out I can take the provider in the webapp and use
@Typed(CustomPrincipal.class) to make that provider only get invoked
when using the subclass. Then, then EJB layer can inject a Principal
and it all works fine.
I like your idea. I can make the EJB have to look up "who is this
user and what are his permissions" based simply on his
Principal.getName(). I can even make the EJB layer handling caching
of those permissions for BOTH the web layer AND the EJB layer. That
doesn't violate my concern that the EJB layer be remotable, and stand
alone from the webapp module.
Thanks for the advice, I very much appreciate it, and another
perspective helped straighten my thinking.
--Chris
On Sun, Jul 15, 2012 at 9:56 PM, Christopher Piggott <cpiggott_at_gmail.com> wrote:
> Unfortunately, injecting a Principal didn't work because I had defined
> a Provider for the CustomPrincipal in the webapp. I was hoping the
> EJB module wouldn't "see" that, but it does:
>
> Error occurred during deployment: Exception while loading the app :
> WELD-001409 Ambiguous dependencies for type [Principal] with
> qualifiers [@Default] at injection point [[field] @Inject
> com.xxxcorp.dao.test.BusinessLogicTestBean.creds]. Possible
> dependencies [[Producer Method [XxxUserPrincipal] with qualifiers
> [@Any @Default] declared as [[method] @Produces @RequestScoped public
> com.xxxscorp.customer.application.SecurityProvider.getuserPrincipal()],
> Built-in Bean [java.security.Principal] with qualifiers [@Default]]].
>
> I could fix this by adding a qualifier to my webapp XxxUserPrincipal
> provider but I don't particularly want to do that. Maybe I will if I
> there is no other way.
>
> Is it possible to declare a @Produces method that's local to just one module?
>
>
>
> On Sun, Jul 15, 2012 at 7:02 PM, Chase <chase_at_osdev.org> wrote:
>> To inject a Principal you just:
>> @Inject private java.security.Principal principal;
>>
>> But I don't know if it would be your custom principal in the EJB tier.
>>
>> What about using an EJB interceptor to determine and obtain all the
>> extra data like the db connection and then placing it in the
>> SessionContext or some CDI managed bean that could be injected
>> wherever you need it in the EJB tier? So instead of trying to
>> propagate the data from the web tier you are using the regular
>> principle to identify the user and then creating the extra data in the
>> ejb tier.
>>
>> -Chase
>>
>> On Sun, Jul 15, 2012 at 8:36 AM, Christopher Piggott <cpiggott_at_gmail.com> wrote:
>>> Hi,
>>>
>>> I have a design question and am looking for some other peoples
>>> thoughts on best practices.
>>>
>>> In one applicaiton (deployed as an .ear) I have a number of projects:
>>> * customer-webapp is a war and is jax-rs (jersey)
>>> * customer-object-model is a bunch of jaxb-annotated beans
>>> * business-logic contains both logic + persistence (will be split out later)
>>>
>>> Not part of the ear:
>>> * glassfish-auth: a custom AppservRealm and
>>> AppservPasswordLoginModule for glassfish
>>>
>>> My authentication layer does the usual thing, but it attaches my own
>>> custom Principal to the Subject. This Principal has extra data
>>> associated with it (beyond just Principal and Groups). This
>>> information includes a pointer to a specific database associated with
>>> that login, as well as some other information about the customer.
>>>
>>> In the webapp I get the Principal from SecurityContext (a jax-rs
>>> class), then if possible safely upcast it to my own Principal.
>>>
>>> The question is: what's the best way to get this to the EJB layer?
>>>
>>>
>>> Things I have tried:
>>>
>>> 1. Create a provider method, in the webapp, to retrieve the
>>> CustomerPrincipal from the SecurityContext, then in the bean:
>>>
>>> @RequestScoped
>>> public class BusinessBean {
>>> @Inject CustomerPrincipal pal;
>>> ...
>>> }
>>>
>>> The terrible thing about this design is that EJB layer can no longer
>>> exist without the webapp. Long term I want to be able to remote the
>>> EJBs so that other applications can make use of the common business
>>> logic and persistence.
>>>
>>>
>>> 2. Try to get the Principal injected directly in, but I can't figure
>>> out how. SessionContext doesn't seem to apply to RequestScoped beans;
>>> RequestContext can't be injected. The only idea I have left is:
>>>
>>> Subject subject = (Subject)
>>> PolicyContext.getContext("javax.security.auth.Subject.container")
>>>
>>> but this seems hackish (?)
>>>
>>> 3. The other idea I had was that I could simply require all users to
>>> pass the extra information into the business logic beans as properties
>>> (i.e. setCustomer(x), setYourDatabase(y). This doesn't seem to fit
>>> the pattern, though, requiring the callers to do stuff beyond what I
>>> would normally expect them to have to know about. The caller just
>>> wants to say "Hi, I'm Fred, and I want you to store this thing." I
>>> would expect the business logic side to be responsible for figuring
>>> out where to store it, in the most efficient manner possible.
>>>
>>>
>>> Does anybody have any experience with patterns/best practices that
>>> relate to this?
>>>
>>> --Chris