Quantcast

Questions after first steps with Shiro

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Questions after first steps with Shiro

Daedalus
Hello everyone, I'm currently evaluating Security Frameworks for my company. We are developing a full JEE 6 Application. So we have a web and ejb project. The Web project is JSF based.
So far Shiro looks really promising in comparison of plain JAAS or jGuard. But I have some additional questions:

1. I want to use a own Login implementation to stay in the JSF universum. I've read in the manual, that for this case I should use org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter. I tried do set it wth this configuration:
ownFilter = org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter
ownFilter.loginUrl = /login.jsf
Is this correct? Because ownFilter.loginUrl = /login.jsf does not work. I get directed to login.jsp everytime. If I use
authc.loginUrl = /login.jsf
it works.
2. My JSF Bean which does the login and logout looks like this:
@Named
@SessionScoped
public class userBean implements Serializable {

    private Subject currentUser = SecurityUtils.getSubject();
    private String name;
    private String password;
	
   public String login() {
       
        if (!currentUser.isAuthenticated()) {
            UsernamePasswordToken token = new UsernamePasswordToken(name, password);
            try {
                currentUser.login(token);
                return "index.jsf?faces-redirect=true";
            } catch (UnknownAccountException uae) {
                FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "User name does not exist", null));
            } catch (IncorrectCredentialsException ice) {
                FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Password is wrong!", null));
            } catch (AuthenticationException lae) {
                FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error during Login", null));
            }
        }
        return null;
    }

    public String logout() {
        currentUser = SecurityUtils.getSubject();
        currentUser.logout();
        return "login.jsf?faces-redirect=true";
    }
	
	//getter setters...
}
The Login does work but is this the correct way to do it?

3. What would be the correct way to use Shiro in an EJB Project?
My goal is to login a user in the web project over a jdbc or ldap realm. But of course the important methods are in the ejb container and need to be protected.
- So how do I use Shiro in the EJB Container?
- Implement the realm in the ejb Project and access it in the web and the ejb container?
- Are Shiro web libraries needed in an EJB Project?

So I really hope someone can answer me my questions because i really would like to use shiro in our project but currently I'm a little bit stuck.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Questions after first steps with Shiro

Les Hazlewood-2
Hi there!

First, let me say welcome to the Shiro community!  Hopefully you'll
find that the framework (and the community) help you greatly along the
way.

Let's see if I can answer your questions inline:

> 1. I want to use a own Login implementation to stay in the JSF universum.
> I've read in the manual, that for this case I should use
> org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter. I tried do
> set it wth this configuration:
>
> ownFilter = org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter
> ownFilter.loginUrl = /login.jsf
>
> Is this correct? Because ownFilter.loginUrl = /login.jsf does not work. I
> get directed to login.jsp everytime. If I use
>
> authc.loginUrl = /login.jsf
>
> it works.

This is quite confusing to me - the 'loginUrl' property on both the
authc filter and your ownFilter come from the same superclass!

If it doesn't work the same way, it is probably a bug.  Could you
please open a Jira issue with a quick sample to test with?

In the meantime, you could try setting the 'shiro.loginUrl =
/login.jsf' property alongside your filter definitions.  This should
work, but it's not an ideal config mechanism since it rather conflicts
with the concept of object-based configuration that INI depends on (it
is a 'special case' - there is no 'shiro' object, which can cause
confusion).

> 2. My JSF Bean which does the login and logout looks like this:
>
> @Named
> @SessionScoped
> public class userBean implements Serializable {
>
>     private Subject currentUser = SecurityUtils.getSubject();
>     private String name;
>     private String password;
>
>    public String login() {
>
>         if (!currentUser.isAuthenticated()) {
>             UsernamePasswordToken token = new UsernamePasswordToken(name,
> password);
>             try {
>                 currentUser.login(token);
>                 return "index.jsf?faces-redirect=true";
>             } catch (UnknownAccountException uae) {
>                 FacesContext.getCurrentInstance().addMessage(null, new
> FacesMessage(FacesMessage.SEVERITY_ERROR, "User name does not exist",
> null));
>             } catch (IncorrectCredentialsException ice) {
>                 FacesContext.getCurrentInstance().addMessage(null, new
> FacesMessage(FacesMessage.SEVERITY_ERROR, "Password is wrong!", null));
>             } catch (AuthenticationException lae) {
>                 FacesContext.getCurrentInstance().addMessage(null, new
> FacesMessage(FacesMessage.SEVERITY_ERROR, "Error during Login", null));
>             }
>         }
>         return null;
>     }
>
>     public String logout() {
>         currentUser = SecurityUtils.getSubject();
>         currentUser.logout();
>         return "login.jsf?faces-redirect=true";
>     }
>
> //getter setters...
> }
>
> The Login does work but is this the correct way to do it?

You should not cache the Subject instance returned from
SecurityUtils.getSubject().  Subject state can change at any time
during a Subject's lifetime with the application, even between threads
(or requests in a web application).

For example, the code above will still execute if another thread
somewhere else authenticated the Subject successfully, which is
probably not desired (the authentication state in your cached Subject
instance does not reflect the authentication state from the other
thread).  The safe bet is to always acquire the Subject as you need
it.

So, if you remove the 'currentUser' class attribute and inline it
inside of your methods, you'll be good - everything else looks great.

>
> 3. What would be the correct way to use Shiro in an EJB Project?

We really should create an EJB sample application that demonstrates
this - it has just been low priority with us working towards
graduation.  If you (or anyone else) would be willing to help with
this, we'd be very grateful - please contact the dev list if you're
interested.

Anyway, much of Shiro's implementation is based on the assumption that
a Subject can always be associated with the currently executing
thread.  So any code can be protected by Shiro - web environment or
not.

In order for this to work properly, there must be some interception
mechanism that creates a Subject instance, binds it to the current
thread, and then cleans up the thread after the execution is complete.
 In web environments, the Shiro Filter does this automatically.  If in
another environment, such as responding to a Remote Method Invocation,
something else must do this 'create/bind/unbind' logic.

So if EJB calls are always made as a result of a web request - you're
100% covered - the Shiro Filter will do all that is required.  If you
have non-web-initiated calls, you'll need to write something that will
do this, typically an AOP interceptor or something similar for EJB
specific mechanisms.

The good news is that if you have to do this, it is very easy - you
can use Shiro's Spring-specific SecureRemoteInvocationExecutor [1]
code as an example to get you started.  If your solution is
EJB-specific, we'd be very much interested in including it in Shiro to
help others in the same situation.  If you find that you need to do
this, please consider contributing it back to the project if possible.

> My goal is to login a user in the web project over a jdbc or ldap realm. But
> of course the important methods are in the ejb container and need to be
> protected.
> - So how do I use Shiro in the EJB Container?

Once the Subject is associated with a thread, AOP is one of easiest
ways of enforcing security restrictions.  Then you can annotate your
EJB methods - for example:

@RequiresRole('bankEmployee')
public void openNewBankAccount() { ... }

or

@RequiresAuthentication
public CreditCardInfo getCreditCardInfo(userId) { ... }

In Shiro's source distribution, there is an AspectJ sample application
that demonstrates this - definitely see if that can be used or
manipulated for your needs.

> - Implement the realm in the ejb Project and access it in the web and the
> ejb container?
> - Are Shiro web libraries needed in an EJB Project?
Only if you want to support web-based access or calls to your EJBs.
If your EJB app is not web-based, you don't need Shiro's web module,
but you will need to ensure the Subject create/bind/unbind logic
executes somehow as described above.

Well, I hope that helps answer your questions!  Please feel free to
continue to ask anything else along the way if you need to do any
coding to get Shiro to work in an EJB app - we'll definitely want to
add that to the project!

Cheers,

Les
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Questions after first steps with Shiro

Les Hazlewood-2
Sorry, forgot the link:

[1] https://svn.apache.org/repos/asf/incubator/shiro/trunk/support/spring/src/main/java/org/apache/shiro/spring/remoting/SecureRemoteInvocationExecutor.java

On Mon, Sep 13, 2010 at 2:45 PM, Les Hazlewood <[hidden email]> wrote:

> Hi there!
>
> First, let me say welcome to the Shiro community!  Hopefully you'll
> find that the framework (and the community) help you greatly along the
> way.
>
> Let's see if I can answer your questions inline:
>
>> 1. I want to use a own Login implementation to stay in the JSF universum.
>> I've read in the manual, that for this case I should use
>> org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter. I tried do
>> set it wth this configuration:
>>
>> ownFilter = org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter
>> ownFilter.loginUrl = /login.jsf
>>
>> Is this correct? Because ownFilter.loginUrl = /login.jsf does not work. I
>> get directed to login.jsp everytime. If I use
>>
>> authc.loginUrl = /login.jsf
>>
>> it works.
>
> This is quite confusing to me - the 'loginUrl' property on both the
> authc filter and your ownFilter come from the same superclass!
>
> If it doesn't work the same way, it is probably a bug.  Could you
> please open a Jira issue with a quick sample to test with?
>
> In the meantime, you could try setting the 'shiro.loginUrl =
> /login.jsf' property alongside your filter definitions.  This should
> work, but it's not an ideal config mechanism since it rather conflicts
> with the concept of object-based configuration that INI depends on (it
> is a 'special case' - there is no 'shiro' object, which can cause
> confusion).
>
>> 2. My JSF Bean which does the login and logout looks like this:
>>
>> @Named
>> @SessionScoped
>> public class userBean implements Serializable {
>>
>>     private Subject currentUser = SecurityUtils.getSubject();
>>     private String name;
>>     private String password;
>>
>>    public String login() {
>>
>>         if (!currentUser.isAuthenticated()) {
>>             UsernamePasswordToken token = new UsernamePasswordToken(name,
>> password);
>>             try {
>>                 currentUser.login(token);
>>                 return "index.jsf?faces-redirect=true";
>>             } catch (UnknownAccountException uae) {
>>                 FacesContext.getCurrentInstance().addMessage(null, new
>> FacesMessage(FacesMessage.SEVERITY_ERROR, "User name does not exist",
>> null));
>>             } catch (IncorrectCredentialsException ice) {
>>                 FacesContext.getCurrentInstance().addMessage(null, new
>> FacesMessage(FacesMessage.SEVERITY_ERROR, "Password is wrong!", null));
>>             } catch (AuthenticationException lae) {
>>                 FacesContext.getCurrentInstance().addMessage(null, new
>> FacesMessage(FacesMessage.SEVERITY_ERROR, "Error during Login", null));
>>             }
>>         }
>>         return null;
>>     }
>>
>>     public String logout() {
>>         currentUser = SecurityUtils.getSubject();
>>         currentUser.logout();
>>         return "login.jsf?faces-redirect=true";
>>     }
>>
>>       //getter setters...
>> }
>>
>> The Login does work but is this the correct way to do it?
>
> You should not cache the Subject instance returned from
> SecurityUtils.getSubject().  Subject state can change at any time
> during a Subject's lifetime with the application, even between threads
> (or requests in a web application).
>
> For example, the code above will still execute if another thread
> somewhere else authenticated the Subject successfully, which is
> probably not desired (the authentication state in your cached Subject
> instance does not reflect the authentication state from the other
> thread).  The safe bet is to always acquire the Subject as you need
> it.
>
> So, if you remove the 'currentUser' class attribute and inline it
> inside of your methods, you'll be good - everything else looks great.
>
>>
>> 3. What would be the correct way to use Shiro in an EJB Project?
>
> We really should create an EJB sample application that demonstrates
> this - it has just been low priority with us working towards
> graduation.  If you (or anyone else) would be willing to help with
> this, we'd be very grateful - please contact the dev list if you're
> interested.
>
> Anyway, much of Shiro's implementation is based on the assumption that
> a Subject can always be associated with the currently executing
> thread.  So any code can be protected by Shiro - web environment or
> not.
>
> In order for this to work properly, there must be some interception
> mechanism that creates a Subject instance, binds it to the current
> thread, and then cleans up the thread after the execution is complete.
>  In web environments, the Shiro Filter does this automatically.  If in
> another environment, such as responding to a Remote Method Invocation,
> something else must do this 'create/bind/unbind' logic.
>
> So if EJB calls are always made as a result of a web request - you're
> 100% covered - the Shiro Filter will do all that is required.  If you
> have non-web-initiated calls, you'll need to write something that will
> do this, typically an AOP interceptor or something similar for EJB
> specific mechanisms.
>
> The good news is that if you have to do this, it is very easy - you
> can use Shiro's Spring-specific SecureRemoteInvocationExecutor [1]
> code as an example to get you started.  If your solution is
> EJB-specific, we'd be very much interested in including it in Shiro to
> help others in the same situation.  If you find that you need to do
> this, please consider contributing it back to the project if possible.
>
>> My goal is to login a user in the web project over a jdbc or ldap realm. But
>> of course the important methods are in the ejb container and need to be
>> protected.
>> - So how do I use Shiro in the EJB Container?
>
> Once the Subject is associated with a thread, AOP is one of easiest
> ways of enforcing security restrictions.  Then you can annotate your
> EJB methods - for example:
>
> @RequiresRole('bankEmployee')
> public void openNewBankAccount() { ... }
>
> or
>
> @RequiresAuthentication
> public CreditCardInfo getCreditCardInfo(userId) { ... }
>
> In Shiro's source distribution, there is an AspectJ sample application
> that demonstrates this - definitely see if that can be used or
> manipulated for your needs.
>
>> - Implement the realm in the ejb Project and access it in the web and the
>> ejb container?
>> - Are Shiro web libraries needed in an EJB Project?
> Only if you want to support web-based access or calls to your EJBs.
> If your EJB app is not web-based, you don't need Shiro's web module,
> but you will need to ensure the Subject create/bind/unbind logic
> executes somehow as described above.
>
> Well, I hope that helps answer your questions!  Please feel free to
> continue to ask anything else along the way if you need to do any
> coding to get Shiro to work in an EJB app - we'll definitely want to
> add that to the project!
>
> Cheers,
>
> Les
>
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Questions after first steps with Shiro

Daedalus
This post was updated on .
Hello, thank you for your detailed answer!

1.
I can inform you it is not a bug. I simply forgot to use this filter in my [urls] section. After I changed
[urls]
/* = authc

to

[urls]
/* = ownFilter
everything worked as expected.

2.
Thanks for the information, I changed my code as suggested.

3.
If I understood you correctly, you say that if my EJB and War Container are deployed on the same machine I could simply use use  SecurityUtils.getSubject();  without further configuration? This would be really great because currently this is our main UseCase.

But if I would use the EJB Container with remote method invocation for example by a "normal" java application or a War deployed on a different machine using the @Remote Interfaces from SessionBeans I need to develop my own bind/unbind mechanism to access the Subject.

Correct?

Also I now have another Question to this EJB Topic. Would it be also a correct solution in a Remote Situation if the caller of the remote method simply sends the password and username of the Subject (encrypted of course) to the EJB Container, the EJB Container authenticates the user again on the same realm as the caller, checks his rights, performs the methods, if the user is allowed to, logged the use out, return the result, if any, to the caller?

This approach sounds easier for me at the moment but maybe this is because I never did AOP before in my life.

If we will develop something generic for ejb container I can't assure you that my company would allow me to donate the code to this project but I promise to ask.

So again thanks for all the information!
Loading...