You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@shiro.apache.org by melvyndekort <me...@mdekort.nl> on 2012/05/30 02:10:28 UTC

Shiro in CDI/JPA2/JSF2 project

Hi all,

I am creating an application using CDI, JPA2 and JSF2.
As a security framework I want to implement Apache Shiro.
This is my first big project using these frameworks, so I don't know the ins
and outs yet...

I have created my own JpaRealm, with simple Entity Beans in combination with
an EntityManager, I don't use any DAOs.
I'm trying to use CDI to inject the EntityManager into my JpaRealm.
Of course this doesn't work since my JpaRealm is not container managed but
is instantiated by Shiro itself.
I've tried injection by using the @PersistenceContext, @PersistenceUnit and
@Inject with a separate Producer.

After some browsing through the Shiro documentation I built my own
WebEnvironment which extends IniWebEnvironment.
But my EntityManager can't be injected here either, since this class is also
not instantiated by the container afaik.
Does anybody know of a way to inject my EntityManager into my JpaRealm?

I can supply my code if needed...

Thank you in advance!

--
View this message in context: http://shiro-user.582556.n2.nabble.com/Shiro-in-CDI-JPA2-JSF2-project-tp7577437.html
Sent from the Shiro User mailing list archive at Nabble.com.

Re: Shiro in CDI/JPA2/JSF2 project

Posted by lprimak <lp...@hope.nyc.ny.us>.
The easiest way to do this is to delegate your JpaRealm into @Stateless EJB,
which can @Inject EntityManager.
You can lookup EntityManager from JNDI as well, but it gets complicated with
resource management there.

Here's some code (untested):
MyBeanLocal beanRef = (MyBeanLocal)new
InitialContext().lookup("java:global/MyBean!com.xxx.beans.MyBeanLocal")
User user = beanRef.getUser("user1")

and the MyBean will take care of all the JPA stuff, which it can do since
its managed by the container.


--
View this message in context: http://shiro-user.582556.n2.nabble.com/Shiro-in-CDI-JPA2-JSF2-project-tp7577437p7577439.html
Sent from the Shiro User mailing list archive at Nabble.com.

Re: Shiro in CDI/JPA2/JSF2 project

Posted by melvyndekort <me...@mdekort.nl>.
Hi,

It's difficult to see what you did without some code.
I've made a simple example of my code and put it on Dropbox.
You can download it here:
http://dl.dropbox.com/u/6753023/shiro_cdi_example.tar.gz

Greetz,

Melvyn



On Tue, Dec 11, 2012 at 5:46 AM, vinnywm [via Shiro User] <
ml-node+s582556n7578034h81@n2.nabble.com> wrote:

> I'm going through the same problem. I've done all the changes recommended
> here but nothing work.
>
> The error that is thrown is: (says it is not a required type of
> WebEnvironment)
>
> WARNING: java.lang.IllegalStateException: ContainerBase.addChild: start:
> org.apache.catalina.LifecycleException:
> org.apache.shiro.config.ConfigurationException: Custom WebEnvironment class
> [br.com.webbiz.saga.control.listener.CdiEnvironmentListener] is not of
> required type [org.apache.shiro.web.env.WebEnvironment]
> java.lang.IllegalStateException: ContainerBase.addChild: start:
> org.apache.catalina.LifecycleException:
> org.apache.shiro.config.ConfigurationException: Custom WebEnvironment class
> [br.com.webbiz.saga.control.listener.CdiEnvironmentListener] is not of
> required type [org.apache.shiro.web.env.WebEnvironment]
>
> What do I do?
>
> ------------------------------
>  If you reply to this email, your message will be added to the discussion
> below:
>
> http://shiro-user.582556.n2.nabble.com/Shiro-in-CDI-JPA2-JSF2-project-tp7577437p7578034.html
>  To unsubscribe from Shiro in CDI/JPA2/JSF2 project, click here<http://shiro-user.582556.n2.nabble.com/template/NamlServlet.jtp?macro=unsubscribe_by_code&node=7577437&code=bWVsdnluQG1kZWtvcnQubmx8NzU3NzQzN3w4NzA5MDUzNzE=>
> .
> NAML<http://shiro-user.582556.n2.nabble.com/template/NamlServlet.jtp?macro=macro_viewer&id=instant_html%21nabble%3Aemail.naml&base=nabble.naml.namespaces.BasicNamespace-nabble.view.web.template.NabbleNamespace-nabble.view.web.template.NodeNamespace&breadcrumbs=notify_subscribers%21nabble%3Aemail.naml-instant_emails%21nabble%3Aemail.naml-send_instant_email%21nabble%3Aemail.naml>
>




--
View this message in context: http://shiro-user.582556.n2.nabble.com/Shiro-in-CDI-JPA2-JSF2-project-tp7577437p7578039.html
Sent from the Shiro User mailing list archive at Nabble.com.

Re: Shiro in CDI/JPA2/JSF2 project

Posted by sh...@xoxy.net.
Sounds like the scenario described here:
https://issues.apache.org/jira/browse/OWB-481

Try adding some logging/print statements to see if the two
ServletContextListeners are being initialized in the expected order. If
not, it looks like you'll need to manually bootstrap OpenWebBeans.

Re: Shiro in CDI/JPA2/JSF2 project

Posted by reinisv <sh...@orbit-x.de>.
Despite the code from Melvyn (thanks man!) and tip from atomicknight
(cheers!) in this thread:
http://shiro-user.582556.n2.nabble.com/Realm-can-not-be-managed-by-CDI-td7502061.html

I still can't manage to make it work :-/

I assume this is caused by my CDI implementation framework (OpenWebbeans)
and the way I am bootstrapping the IoC container.

What happens is that in my customized EnvironmentLoaderListener the injected
Realm is null. I attempted to inject some of my beans and debugging showed
that injection is not working at all.

I know this is only indirectly related to shiro, but still could be useful
for anyone who will attempt to enable OWB CDI in shiro.

So my question is this - based on web.xml, is the issue that OWB is also
bootstrapping through ServletContextListerner? Or are there some other
obvious errors that would cause IoC not to work in my customized
EnvironmentLoaderListener?

web.xml
-----------------------------
	<listener>
	
<listener-class>org.apache.webbeans.servlet.WebBeansConfigurationListener</listener-class>
	</listener>
	<listener>
	
<listener-class>myco.web.filter.CdiWebEnvironmentLoaderListener</listener-class>
	</listener>
	<listener>
	
<listener-class>org.apache.myfaces.webapp.StartupServletContextListener</listener-class>
	</listener>

	
	<filter>
		<filter-name>ShiroFilter</filter-name>
		<filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
	</filter>

	<filter-mapping>
		<filter-name>ShiroFilter</filter-name>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

	<servlet>
		<servlet-name>Faces Servlet</servlet-name>
		<servlet-class>org.apache.myfaces.webapp.MyFacesServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>*.xhtml</url-pattern>
	</servlet-mapping>
--------------------------------------

Thank you for your help
Reinis



--
View this message in context: http://shiro-user.582556.n2.nabble.com/Shiro-in-CDI-JPA2-JSF2-project-tp7577437p7577848.html
Sent from the Shiro User mailing list archive at Nabble.com.

Re: Shiro in CDI/JPA2/JSF2 project

Posted by melvyndekort <me...@mdekort.nl>.
I've been doing some debugging and I found the cause.
Instead of configuring the ShiroFilter in my web.xml I had the
*Ini*ShiroFilter configured.
The IniShiroFilter creates a new SecurityManager from the ini file.
This new SecurityManager didn't know about the realm I've added in my
EnvironmentLoader, so it didn't have any realms.
I replaced it with the ShiroFilter in my web.xml and all seems to be working
now with my CdiEnvironmentLoaderListener.

Thank you for your help atomicknight!
If anybody with the same issues wants a sample of my configuration, just
mail me.


atomicknight wrote
> 
> Nothing looks obviously wrong to me - I'm fairly certain that the
> SecurityManager should not be overwritten by any other systems. Have you
> checked your server logs for exceptions or error messages? It may also be
> helpful to attach a debugger to see if the initialization is actually
> occurring as you'd expect.
> 

--
View this message in context: http://shiro-user.582556.n2.nabble.com/Shiro-in-CDI-JPA2-JSF2-project-tp7577437p7577466.html
Sent from the Shiro User mailing list archive at Nabble.com.

Re: Shiro in CDI/JPA2/JSF2 project

Posted by sh...@xoxy.net.
Nothing looks obviously wrong to me - I'm fairly certain that the
SecurityManager should not be overwritten by any other systems. Have you
checked your server logs for exceptions or error messages? It may also be
helpful to attach a debugger to see if the initialization is actually
occurring as you'd expect.


On Sun, Jun 3, 2012 at 11:55 AM, melvyndekort - melvyn@mdekort.nl wrote:

> I've created an extended EnvironmentLoaderListener.
> But I see now when I try to login that my securityManger has no realms
> available.
> Do you know if my securityManager could be overwritten somewhere?
>
> public class CdiEnvironmentLoaderListener extends EnvironmentLoaderListener
> {
>  @Inject
>   JpaRealm jpaRealm;
>
>  @Override
>  protected WebEnvironment createEnvironment(ServletContext sc) {
>    WebEnvironment environment = super.createEnvironment(sc);
>
>    RealmSecurityManager rsm = (RealmSecurityManager)
> environment.getSecurityManager();
>
>    HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
>     matcher.setHashAlgorithmName(Sha256Hash.ALGORITHM_NAME);
>
>    jpaRealm.setCredentialsMatcher(matcher);
>
>    rsm.setRealm(jpaRealm);
>
>    ((DefaultWebEnvironment) environment).setSecurityManager(rsm);
>
>    return environment;
>  }
> }
>
>
> atomicknight wrote
> >
> > You can't use the built-in EnvironmentLoaderListener because it doesn't
> > use
> > injection to build the Environment. However, you should be able to extend
> > it and override #createEnvironment(ServletContext) to use an injected
> > CdiWebEnvironment instance:
> >
> > public class CdiEnvironmentLoaderListener extends
> > EnvironmentLoaderListener
> > {
> >   @Inject
> >   private CdiWebEnvironment environment;
> >
> >   protected WebEnvironment createEnvironment(ServletContext sc) {
> > // Do your initialization here
> > return environment;
> > }
> > }
> >
> > I haven't actually tried this because I ended up writing my own
> > version of EnvironmentLoaderListener,
> > but this should work.
> >
>
> --
> View this message in context:
> http://shiro-user.582556.n2.nabble.com/Shiro-in-CDI-JPA2-JSF2-project-tp7577437p7577461.html
> Sent from the Shiro User mailing list archive at Nabble.com.
>
>

Re: Shiro in CDI/JPA2/JSF2 project

Posted by melvyndekort <me...@mdekort.nl>.
I've created an extended EnvironmentLoaderListener.
But I see now when I try to login that my securityManger has no realms
available.
Do you know if my securityManager could be overwritten somewhere?

public class CdiEnvironmentLoaderListener extends EnvironmentLoaderListener
{
  @Inject
  JpaRealm jpaRealm;

  @Override
  protected WebEnvironment createEnvironment(ServletContext sc) {
    WebEnvironment environment = super.createEnvironment(sc);

    RealmSecurityManager rsm = (RealmSecurityManager)
environment.getSecurityManager();

    HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
    matcher.setHashAlgorithmName(Sha256Hash.ALGORITHM_NAME);

    jpaRealm.setCredentialsMatcher(matcher);

    rsm.setRealm(jpaRealm);

    ((DefaultWebEnvironment) environment).setSecurityManager(rsm);

    return environment;
  }
}


atomicknight wrote
> 
> You can't use the built-in EnvironmentLoaderListener because it doesn't
> use
> injection to build the Environment. However, you should be able to extend
> it and override #createEnvironment(ServletContext) to use an injected
> CdiWebEnvironment instance:
> 
> public class CdiEnvironmentLoaderListener extends
> EnvironmentLoaderListener
> {
>   @Inject
>   private CdiWebEnvironment environment;
> 
>   protected WebEnvironment createEnvironment(ServletContext sc) {
> // Do your initialization here
> return environment;
> }
> }
> 
> I haven't actually tried this because I ended up writing my own
> version of EnvironmentLoaderListener,
> but this should work.
> 

--
View this message in context: http://shiro-user.582556.n2.nabble.com/Shiro-in-CDI-JPA2-JSF2-project-tp7577437p7577461.html
Sent from the Shiro User mailing list archive at Nabble.com.

Re: Shiro in CDI/JPA2/JSF2 project

Posted by sh...@xoxy.net.
You can't use the built-in EnvironmentLoaderListener because it doesn't use
injection to build the Environment. However, you should be able to extend
it and override #createEnvironment(ServletContext) to use an injected
CdiWebEnvironment instance:

public class CdiEnvironmentLoaderListener extends EnvironmentLoaderListener
{
  @Inject
  private CdiWebEnvironment environment;

  protected WebEnvironment createEnvironment(ServletContext sc) {
// Do your initialization here
return environment;
}
}

I haven't actually tried this because I ended up writing my own
version of EnvironmentLoaderListener,
but this should work.


On Wed, May 30, 2012 at 7:55 AM, melvyndekort - melvyn@mdekort.nl wrote:

> I don't seem to get it all to work.
> I have my own WebEnvironment and try to inject the JpaRealm into it.
> The problem seems to be that the JpaRealm is not instantiated and is not
> injected into the CdiWebEnvironment.
>
> This is basically what I currently have:
>
> ### WEB.XML SNIPPET ###
>
>  <context-param>
>    <param-name>shiroEnvironmentClass</param-name>
>    <param-value>****.shiro.CdiWebEnvironment</param-value>
>  </context-param>
>
>  <listener>
>
>
> <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
>  </listener>
>
>
> ### SHIRO.INI ###
>
> [main]
> authc = org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter
> authc.loginUrl = /login.jsf
>
> [users]
>
> [roles]
>
> [urls]
> /login.jsf = authc
> /secure/** = authc
>
>
> ### CUSTOM WEB ENVIRONMENT ###
>
> @ApplicationScoped
> public class CdiWebEnvironment extends IniWebEnvironment
> {
>  private static Logger LOG = Logger.getLogger(CdiWebEnvironment.class);
>
>  @Inject
>  private JpaRealm jpaRealm;
>
>  @Inject
>  public CdiWebEnvironment() {
>    LOG.debug("CdiWebEnvironment instantiated!");
>  }
>
>  @Override
>  protected void configure() {
>    super.configure();
> /* WHILE DEBUGGING jpaRealm IS NULL AT THIS POINT! */
>
>
>    RealmSecurityManager securityManager = (RealmSecurityManager)
> getSecurityManager();
>    securityManager.setRealm(jpaRealm);
>  }
> }
>
>
> ### JPA REALM CLASS ###
>
> @ApplicationScoped
> public class JpaRealm extends AuthorizingRealm
> {
>  private static Logger LOG = Logger.getLogger(JpaRealm.class);
>
>  @PersistenceContext
>  private EntityManager entityManager;
>
>  public JpaRealm() {
> /* THIS LINE IS NEVER REACHED, SO NO INSTANCE IS CREATED! */
>
>    setName("JpaRealm");
>
>    HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
>    matcher.setHashAlgorithmName("SHA-256");
>    setCredentialsMatcher(matcher);
>
>    LOG.debug("JpaRealm instantiated!");
>  }
>
>  @Override
>  protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken
> authenticationToken) { ... }
>
>  @Override
>  protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection
> principals) { ... }
> }
>
>
> atomicknight wrote
> >
> > The Environment is loaded by a servlet context listener, which is managed
> > by the container and consequently supports injection. Then it's just a
> > matter of injecting your JpaRealm, building a WebSecurityManager from it,
> > and associating the SecurityManager with the Environment.
> >
>
> --
> View this message in context:
> http://shiro-user.582556.n2.nabble.com/Shiro-in-CDI-JPA2-JSF2-project-tp7577437p7577442.html
> Sent from the Shiro User mailing list archive at Nabble.com.
>
>

Re: Shiro in CDI/JPA2/JSF2 project

Posted by melvyndekort <me...@mdekort.nl>.
I don't seem to get it all to work.
I have my own WebEnvironment and try to inject the JpaRealm into it.
The problem seems to be that the JpaRealm is not instantiated and is not
injected into the CdiWebEnvironment.

This is basically what I currently have:

### WEB.XML SNIPPET ###

  <context-param>
    <param-name>shiroEnvironmentClass</param-name>
    <param-value>****.shiro.CdiWebEnvironment</param-value>
  </context-param>
  
  <listener>
   
<listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
  </listener>


### SHIRO.INI ###

[main]
authc = org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter
authc.loginUrl = /login.jsf

[users]

[roles]

[urls]
/login.jsf = authc
/secure/** = authc


### CUSTOM WEB ENVIRONMENT ###

@ApplicationScoped
public class CdiWebEnvironment extends IniWebEnvironment
{
  private static Logger LOG = Logger.getLogger(CdiWebEnvironment.class);

  @Inject
  private JpaRealm jpaRealm;

  @Inject
  public CdiWebEnvironment() {
    LOG.debug("CdiWebEnvironment instantiated!");
  }

  @Override
  protected void configure() {
    super.configure(); 
/* WHILE DEBUGGING jpaRealm IS NULL AT THIS POINT! */


    RealmSecurityManager securityManager = (RealmSecurityManager)
getSecurityManager();
    securityManager.setRealm(jpaRealm);
  }
}


### JPA REALM CLASS ###

@ApplicationScoped
public class JpaRealm extends AuthorizingRealm
{
  private static Logger LOG = Logger.getLogger(JpaRealm.class);

  @PersistenceContext
  private EntityManager entityManager;

  public JpaRealm() { 
/* THIS LINE IS NEVER REACHED, SO NO INSTANCE IS CREATED! */

    setName("JpaRealm");

    HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
    matcher.setHashAlgorithmName("SHA-256");
    setCredentialsMatcher(matcher);

    LOG.debug("JpaRealm instantiated!");
  }

  @Override
  protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken
authenticationToken) { ... }

  @Override
  protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection
principals) { ... }
}


atomicknight wrote
> 
> The Environment is loaded by a servlet context listener, which is managed
> by the container and consequently supports injection. Then it's just a
> matter of injecting your JpaRealm, building a WebSecurityManager from it,
> and associating the SecurityManager with the Environment.
> 

--
View this message in context: http://shiro-user.582556.n2.nabble.com/Shiro-in-CDI-JPA2-JSF2-project-tp7577437p7577442.html
Sent from the Shiro User mailing list archive at Nabble.com.

Re: Shiro in CDI/JPA2/JSF2 project

Posted by sh...@xoxy.net.
The Environment is loaded by a servlet context listener, which is managed
by the container and consequently supports injection. Then it's just a
matter of injecting your JpaRealm, building a WebSecurityManager from it,
and associating the SecurityManager with the Environment.


On Tue, May 29, 2012 at 8:10 PM, melvyndekort - melvyn@mdekort.nl wrote:

> Hi all,
>
> I am creating an application using CDI, JPA2 and JSF2.
> As a security framework I want to implement Apache Shiro.
> This is my first big project using these frameworks, so I don't know the
> ins
> and outs yet...
>
> I have created my own JpaRealm, with simple Entity Beans in combination
> with
> an EntityManager, I don't use any DAOs.
> I'm trying to use CDI to inject the EntityManager into my JpaRealm.
> Of course this doesn't work since my JpaRealm is not container managed but
> is instantiated by Shiro itself.
> I've tried injection by using the @PersistenceContext, @PersistenceUnit and
> @Inject with a separate Producer.
>
> After some browsing through the Shiro documentation I built my own
> WebEnvironment which extends IniWebEnvironment.
> But my EntityManager can't be injected here either, since this class is
> also
> not instantiated by the container afaik.
> Does anybody know of a way to inject my EntityManager into my JpaRealm?
>
> I can supply my code if needed...
>
> Thank you in advance!
>
> --
> View this message in context:
> http://shiro-user.582556.n2.nabble.com/Shiro-in-CDI-JPA2-JSF2-project-tp7577437.html
> Sent from the Shiro User mailing list archive at Nabble.com.
>
>