Multiple passwords

classic Classic list List threaded Threaded
17 messages Options
Reply | Threaded
Open this post in threaded view
|

Multiple passwords

Bengt Rodehav
I have created a custom authentication filter that only allows access from white listed IP addresses. I configure this using an access token instead of a user and the IP address instead of the password. An example:

accessToken1=123.123.123.123,publicApi

However, some customers have more than one public IP address that need to access our API. What is the recommended way of supporting something like that? I don't think it is possible to list multiple passwords which would be needed using our existing strategy.

Is there some class/interface I could subclass/implement to enable the authentication to accept any password in a list of passwords?

/Bengt
Reply | Threaded
Open this post in threaded view
|

Re: Multiple passwords

armandoxxx
This post was updated on .
extend AccessControlFilter and override method :

isAccessAllowed(ServletRequest request, ServletResponse arg1, Object arg2) throws Exception {
  Object principal = SecurityUtils.getSubject().getPrincipal();

 String ipAddress =  request.getRemoteAddr();
 // load principal IP addresses from somwhere 
 List<String> ipAddresses = ... 

 return ipAddreses.contains(ipAddress));

}

regards Armando

PS: don't forget all the IFs and stuff to check what needs to be checked.



--
Sent from: http://shiro-user.582556.n2.nabble.com/
Reply | Threaded
Open this post in threaded view
|

Re: Multiple passwords

Brian Demers
As far as accepting multiple password's go, you would need to implement a custom realm (or extend an existing one):

On Mon, Nov 19, 2018 at 9:09 AM armandoxxx <[hidden email]> wrote:
Implement AccessControlFilter

method :


regards Armando



--
Sent from: http://shiro-user.582556.n2.nabble.com/
Reply | Threaded
Open this post in threaded view
|

Re: Multiple passwords

Bengt Rodehav
Thanks for the advice Brian.

A custom realm sounds like a lot of work but maybe it's not that hard if I extend the existing realm. Not sure which one that is though. I juse INI configuration and the users are listed under "[users]". What realm do I use then? How do I instead specify that my custom realm should be used?

/Bengt

Den mån 19 nov. 2018 kl 15:32 skrev Brian Demers <[hidden email]>:
As far as accepting multiple password's go, you would need to implement a custom realm (or extend an existing one):

On Mon, Nov 19, 2018 at 9:09 AM armandoxxx <[hidden email]> wrote:
Implement AccessControlFilter

method :


regards Armando



--
Sent from: http://shiro-user.582556.n2.nabble.com/
Reply | Threaded
Open this post in threaded view
|

Re: Multiple passwords

Brian Demers
I'm not sure I'm following 100%. Why do your users need multiple passwords if you are defining them statically in an ini file?  Maybe we can point you to a solution one we have a better idea of what you are trying to to?

On Mon, Nov 19, 2018 at 10:34 AM Bengt Rodehav <[hidden email]> wrote:
Thanks for the advice Brian.

A custom realm sounds like a lot of work but maybe it's not that hard if I extend the existing realm. Not sure which one that is though. I juse INI configuration and the users are listed under "[users]". What realm do I use then? How do I instead specify that my custom realm should be used?

/Bengt

Den mån 19 nov. 2018 kl 15:32 skrev Brian Demers <[hidden email]>:
As far as accepting multiple password's go, you would need to implement a custom realm (or extend an existing one):

On Mon, Nov 19, 2018 at 9:09 AM armandoxxx <[hidden email]> wrote:
Implement AccessControlFilter

method :


regards Armando



--
Sent from: http://shiro-user.582556.n2.nabble.com/
Reply | Threaded
Open this post in threaded view
|

Re: Multiple passwords

armandoxxx
In reply to this post by Bengt Rodehav
Hey ...

Please explain what would you like to achieve (your use case) .. we will try
to help you how to implement it ;) .. Sorry I'm lost too ...

Regards
Armando



--
Sent from: http://shiro-user.582556.n2.nabble.com/
Reply | Threaded
Open this post in threaded view
|

Re: Multiple passwords

Bengt Rodehav
Sorry for being unclear. I'll try to explain better.

We have a REST API that partners to us can access. It is a simple http/GET based protocol that returns JSON data. Authentication is being done via a parameter "accessToken" in the URL (https://....?acessToken=123). The access token is similar to a user. We don't require a password since the accessToken itself is a random GUID. We do, however, only allow access from known IP addresses (white listing). Generally speaking, this is a public site so the firewall restricts no one. But this API needs to be restricted to known IP addresses.

Currently I have created a filter (I have subclassed AuthenticatingFilter) with my own createToken() method. In that method, I extract the access token and the IP address (either from the ServletRequest's getRemoteAddr() or from the "X-Forwarded-For" header). I then create a UsernamePasswordToken with the access token as the user and the IP address as the password.

The number of users accessing this service is not very high so it is easy to maintain them in the ini file as follows:

[users]
accessToken1=123.123.123.123,publicApi
accessToken2=456.456.456.456,publicApi

...where "publicApi" is the role I require for accessing this service.

This approach is really easy and works but it only allows for one IP address per access token which is a limitation for us. Some customers need to access our service from multiple servers and sometimes from an IP address range.

So I need another solution. One solution is of course to use the firewall for white listing. We do that for a number of other services where we only allow access from our partners. However, in this case the site is public except for this exact call. This makes it hard for us to use our firewall. Also, it would be nice to maintain the access tokens and the IP addresses in one place. Otherwise the risk is very high that the firewall will, after a while, not be synced with the access tokens.

I am very open to other approaches. I just took an easy first route that seemed to work fine - for a while...

/Bengt








Den tis 20 nov. 2018 kl 07:21 skrev armandoxxx <[hidden email]>:
Hey ...

Please explain what would you like to achieve (your use case) .. we will try
to help you how to implement it ;) .. Sorry I'm lost too ...

Regards
Armando



--
Sent from: http://shiro-user.582556.n2.nabble.com/
Reply | Threaded
Open this post in threaded view
|

Re: Multiple passwords

Philip Whitehouse
Okay..

I’m pseudo-coding here but:

Firstly your accessToken is not just your username. It’s also your password. The reason for this is that it’s the secret that authenticates a user. You currently aren’t storing a real username. The IP address isn’t secret - it’s not your password. It’s just a filter.

Tbh the deficiency in Shiro here is that there’s no AuthToken-based Token implementation. That would have encouraged the right solution from the start.

What you want is a config like the following:

accessToken1=accessToken1,publicApi
accessToken2=accessToken2.publicApi

and then separately

[allowedIPs]
accessToken1=ip1,ip2

and then your filter says:

if(!allowedIPs.get(accessToken).contains(ip1) {
   throw new AuthenticationFailedException();
}

What you need to do is implement a Shiro Ini reader that help you do the second bit. There might even be existing IP filters for Shiro out there. A quick search looks promising.

Best,

Philip Whitehouse

On 20 Nov 2018, at 07:38, Bengt Rodehav <[hidden email]> wrote:

Sorry for being unclear. I'll try to explain better.

We have a REST API that partners to us can access. It is a simple http/GET based protocol that returns JSON data. Authentication is being done via a parameter "accessToken" in the URL (https://....?acessToken=123). The access token is similar to a user. We don't require a password since the accessToken itself is a random GUID. We do, however, only allow access from known IP addresses (white listing). Generally speaking, this is a public site so the firewall restricts no one. But this API needs to be restricted to known IP addresses.

Currently I have created a filter (I have subclassed AuthenticatingFilter) with my own createToken() method. In that method, I extract the access token and the IP address (either from the ServletRequest's getRemoteAddr() or from the "X-Forwarded-For" header). I then create a UsernamePasswordToken with the access token as the user and the IP address as the password.

The number of users accessing this service is not very high so it is easy to maintain them in the ini file as follows:

[users]
accessToken1=123.123.123.123,publicApi
accessToken2=456.456.456.456,publicApi

...where "publicApi" is the role I require for accessing this service.

This approach is really easy and works but it only allows for one IP address per access token which is a limitation for us. Some customers need to access our service from multiple servers and sometimes from an IP address range.

So I need another solution. One solution is of course to use the firewall for white listing. We do that for a number of other services where we only allow access from our partners. However, in this case the site is public except for this exact call. This makes it hard for us to use our firewall. Also, it would be nice to maintain the access tokens and the IP addresses in one place. Otherwise the risk is very high that the firewall will, after a while, not be synced with the access tokens.

I am very open to other approaches. I just took an easy first route that seemed to work fine - for a while...

/Bengt








Den tis 20 nov. 2018 kl 07:21 skrev armandoxxx <[hidden email]>:
Hey ...

Please explain what would you like to achieve (your use case) .. we will try
to help you how to implement it ;) .. Sorry I'm lost too ...

Regards
Armando



--
Sent from: http://shiro-user.582556.n2.nabble.com/
Reply | Threaded
Open this post in threaded view
|

Re: Multiple passwords

Bengt Rodehav
Great advice Philip - and yes you're right; the access token is both the username and the password. I think this is best practice in a token based authentication scenario.

I think I can come up with a way to link the access token to a list of IP addresses. Just a question, the code you wrote where you check "(if(!allowedIPSs.get...)". In what method would I do that? And what existing filter is best to extend?

I actually think that our approach is pretty common in a REST scenario. Perhaps even common enough for Shiro to support it...

/Bengt

Den tis 20 nov. 2018 kl 10:54 skrev Philip Whitehouse <[hidden email]>:
Okay..

I’m pseudo-coding here but:

Firstly your accessToken is not just your username. It’s also your password. The reason for this is that it’s the secret that authenticates a user. You currently aren’t storing a real username. The IP address isn’t secret - it’s not your password. It’s just a filter.

Tbh the deficiency in Shiro here is that there’s no AuthToken-based Token implementation. That would have encouraged the right solution from the start.

What you want is a config like the following:

accessToken1=accessToken1,publicApi
accessToken2=accessToken2.publicApi

and then separately

[allowedIPs]
accessToken1=ip1,ip2

and then your filter says:

if(!allowedIPs.get(accessToken).contains(ip1) {
   throw new AuthenticationFailedException();
}

What you need to do is implement a Shiro Ini reader that help you do the second bit. There might even be existing IP filters for Shiro out there. A quick search looks promising.

Best,

Philip Whitehouse

On 20 Nov 2018, at 07:38, Bengt Rodehav <[hidden email]> wrote:

Sorry for being unclear. I'll try to explain better.

We have a REST API that partners to us can access. It is a simple http/GET based protocol that returns JSON data. Authentication is being done via a parameter "accessToken" in the URL (https://....?acessToken=123). The access token is similar to a user. We don't require a password since the accessToken itself is a random GUID. We do, however, only allow access from known IP addresses (white listing). Generally speaking, this is a public site so the firewall restricts no one. But this API needs to be restricted to known IP addresses.

Currently I have created a filter (I have subclassed AuthenticatingFilter) with my own createToken() method. In that method, I extract the access token and the IP address (either from the ServletRequest's getRemoteAddr() or from the "X-Forwarded-For" header). I then create a UsernamePasswordToken with the access token as the user and the IP address as the password.

The number of users accessing this service is not very high so it is easy to maintain them in the ini file as follows:

[users]
accessToken1=123.123.123.123,publicApi
accessToken2=456.456.456.456,publicApi

...where "publicApi" is the role I require for accessing this service.

This approach is really easy and works but it only allows for one IP address per access token which is a limitation for us. Some customers need to access our service from multiple servers and sometimes from an IP address range.

So I need another solution. One solution is of course to use the firewall for white listing. We do that for a number of other services where we only allow access from our partners. However, in this case the site is public except for this exact call. This makes it hard for us to use our firewall. Also, it would be nice to maintain the access tokens and the IP addresses in one place. Otherwise the risk is very high that the firewall will, after a while, not be synced with the access tokens.

I am very open to other approaches. I just took an easy first route that seemed to work fine - for a while...

/Bengt








Den tis 20 nov. 2018 kl 07:21 skrev armandoxxx <[hidden email]>:
Hey ...

Please explain what would you like to achieve (your use case) .. we will try
to help you how to implement it ;) .. Sorry I'm lost too ...

Regards
Armando



--
Sent from: http://shiro-user.582556.n2.nabble.com/
Reply | Threaded
Open this post in threaded view
|

Re: Multiple passwords

Brian Demers
I'd also caution the use of this UID in a GET request.  It sounds like it might be suspectable to cross-site scripting attacks.
If I could figure out what the uuid, it would probably be easy to phish a user to an attacker site, and make the GET request

On Tue, Nov 20, 2018 at 8:35 AM Bengt Rodehav <[hidden email]> wrote:
Great advice Philip - and yes you're right; the access token is both the username and the password. I think this is best practice in a token based authentication scenario.

I think I can come up with a way to link the access token to a list of IP addresses. Just a question, the code you wrote where you check "(if(!allowedIPSs.get...)". In what method would I do that? And what existing filter is best to extend?

I actually think that our approach is pretty common in a REST scenario. Perhaps even common enough for Shiro to support it...

/Bengt

Den tis 20 nov. 2018 kl 10:54 skrev Philip Whitehouse <[hidden email]>:
Okay..

I’m pseudo-coding here but:

Firstly your accessToken is not just your username. It’s also your password. The reason for this is that it’s the secret that authenticates a user. You currently aren’t storing a real username. The IP address isn’t secret - it’s not your password. It’s just a filter.

Tbh the deficiency in Shiro here is that there’s no AuthToken-based Token implementation. That would have encouraged the right solution from the start.

What you want is a config like the following:

accessToken1=accessToken1,publicApi
accessToken2=accessToken2.publicApi

and then separately

[allowedIPs]
accessToken1=ip1,ip2

and then your filter says:

if(!allowedIPs.get(accessToken).contains(ip1) {
   throw new AuthenticationFailedException();
}

What you need to do is implement a Shiro Ini reader that help you do the second bit. There might even be existing IP filters for Shiro out there. A quick search looks promising.

Best,

Philip Whitehouse

On 20 Nov 2018, at 07:38, Bengt Rodehav <[hidden email]> wrote:

Sorry for being unclear. I'll try to explain better.

We have a REST API that partners to us can access. It is a simple http/GET based protocol that returns JSON data. Authentication is being done via a parameter "accessToken" in the URL (https://....?acessToken=123). The access token is similar to a user. We don't require a password since the accessToken itself is a random GUID. We do, however, only allow access from known IP addresses (white listing). Generally speaking, this is a public site so the firewall restricts no one. But this API needs to be restricted to known IP addresses.

Currently I have created a filter (I have subclassed AuthenticatingFilter) with my own createToken() method. In that method, I extract the access token and the IP address (either from the ServletRequest's getRemoteAddr() or from the "X-Forwarded-For" header). I then create a UsernamePasswordToken with the access token as the user and the IP address as the password.

The number of users accessing this service is not very high so it is easy to maintain them in the ini file as follows:

[users]
accessToken1=123.123.123.123,publicApi
accessToken2=456.456.456.456,publicApi

...where "publicApi" is the role I require for accessing this service.

This approach is really easy and works but it only allows for one IP address per access token which is a limitation for us. Some customers need to access our service from multiple servers and sometimes from an IP address range.

So I need another solution. One solution is of course to use the firewall for white listing. We do that for a number of other services where we only allow access from our partners. However, in this case the site is public except for this exact call. This makes it hard for us to use our firewall. Also, it would be nice to maintain the access tokens and the IP addresses in one place. Otherwise the risk is very high that the firewall will, after a while, not be synced with the access tokens.

I am very open to other approaches. I just took an easy first route that seemed to work fine - for a while...

/Bengt








Den tis 20 nov. 2018 kl 07:21 skrev armandoxxx <[hidden email]>:
Hey ...

Please explain what would you like to achieve (your use case) .. we will try
to help you how to implement it ;) .. Sorry I'm lost too ...

Regards
Armando



--
Sent from: http://shiro-user.582556.n2.nabble.com/
Reply | Threaded
Open this post in threaded view
|

Re: Multiple passwords

Bengt Rodehav
Yeah - it's probably not foolproof. But we do use https and we do add the extra layer of white listing the IP address. Would you still consider it insecure?

/Bengt

Den tis 20 nov. 2018 kl 16:00 skrev Brian Demers <[hidden email]>:
I'd also caution the use of this UID in a GET request.  It sounds like it might be suspectable to cross-site scripting attacks.
If I could figure out what the uuid, it would probably be easy to phish a user to an attacker site, and make the GET request

On Tue, Nov 20, 2018 at 8:35 AM Bengt Rodehav <[hidden email]> wrote:
Great advice Philip - and yes you're right; the access token is both the username and the password. I think this is best practice in a token based authentication scenario.

I think I can come up with a way to link the access token to a list of IP addresses. Just a question, the code you wrote where you check "(if(!allowedIPSs.get...)". In what method would I do that? And what existing filter is best to extend?

I actually think that our approach is pretty common in a REST scenario. Perhaps even common enough for Shiro to support it...

/Bengt

Den tis 20 nov. 2018 kl 10:54 skrev Philip Whitehouse <[hidden email]>:
Okay..

I’m pseudo-coding here but:

Firstly your accessToken is not just your username. It’s also your password. The reason for this is that it’s the secret that authenticates a user. You currently aren’t storing a real username. The IP address isn’t secret - it’s not your password. It’s just a filter.

Tbh the deficiency in Shiro here is that there’s no AuthToken-based Token implementation. That would have encouraged the right solution from the start.

What you want is a config like the following:

accessToken1=accessToken1,publicApi
accessToken2=accessToken2.publicApi

and then separately

[allowedIPs]
accessToken1=ip1,ip2

and then your filter says:

if(!allowedIPs.get(accessToken).contains(ip1) {
   throw new AuthenticationFailedException();
}

What you need to do is implement a Shiro Ini reader that help you do the second bit. There might even be existing IP filters for Shiro out there. A quick search looks promising.

Best,

Philip Whitehouse

On 20 Nov 2018, at 07:38, Bengt Rodehav <[hidden email]> wrote:

Sorry for being unclear. I'll try to explain better.

We have a REST API that partners to us can access. It is a simple http/GET based protocol that returns JSON data. Authentication is being done via a parameter "accessToken" in the URL (https://....?acessToken=123). The access token is similar to a user. We don't require a password since the accessToken itself is a random GUID. We do, however, only allow access from known IP addresses (white listing). Generally speaking, this is a public site so the firewall restricts no one. But this API needs to be restricted to known IP addresses.

Currently I have created a filter (I have subclassed AuthenticatingFilter) with my own createToken() method. In that method, I extract the access token and the IP address (either from the ServletRequest's getRemoteAddr() or from the "X-Forwarded-For" header). I then create a UsernamePasswordToken with the access token as the user and the IP address as the password.

The number of users accessing this service is not very high so it is easy to maintain them in the ini file as follows:

[users]
accessToken1=123.123.123.123,publicApi
accessToken2=456.456.456.456,publicApi

...where "publicApi" is the role I require for accessing this service.

This approach is really easy and works but it only allows for one IP address per access token which is a limitation for us. Some customers need to access our service from multiple servers and sometimes from an IP address range.

So I need another solution. One solution is of course to use the firewall for white listing. We do that for a number of other services where we only allow access from our partners. However, in this case the site is public except for this exact call. This makes it hard for us to use our firewall. Also, it would be nice to maintain the access tokens and the IP addresses in one place. Otherwise the risk is very high that the firewall will, after a while, not be synced with the access tokens.

I am very open to other approaches. I just took an easy first route that seemed to work fine - for a while...

/Bengt








Den tis 20 nov. 2018 kl 07:21 skrev armandoxxx <[hidden email]>:
Hey ...

Please explain what would you like to achieve (your use case) .. we will try
to help you how to implement it ;) .. Sorry I'm lost too ...

Regards
Armando



--
Sent from: http://shiro-user.582556.n2.nabble.com/
Reply | Threaded
Open this post in threaded view
|

Re: Multiple passwords

Brian Demers
Just get one of your users to click on a link that looks something like this, https://your-company.evil.com/index.html :

<html>

Granted this relies on getting one of these uuid's, but since they are long-lived the chance of them leaking grows with time (and are likely managed by people?)

Does that help?

On Tue, Nov 20, 2018 at 11:02 AM Bengt Rodehav <[hidden email]> wrote:
Yeah - it's probably not foolproof. But we do use https and we do add the extra layer of white listing the IP address. Would you still consider it insecure?

/Bengt

Den tis 20 nov. 2018 kl 16:00 skrev Brian Demers <[hidden email]>:
I'd also caution the use of this UID in a GET request.  It sounds like it might be suspectable to cross-site scripting attacks.
If I could figure out what the uuid, it would probably be easy to phish a user to an attacker site, and make the GET request

On Tue, Nov 20, 2018 at 8:35 AM Bengt Rodehav <[hidden email]> wrote:
Great advice Philip - and yes you're right; the access token is both the username and the password. I think this is best practice in a token based authentication scenario.

I think I can come up with a way to link the access token to a list of IP addresses. Just a question, the code you wrote where you check "(if(!allowedIPSs.get...)". In what method would I do that? And what existing filter is best to extend?

I actually think that our approach is pretty common in a REST scenario. Perhaps even common enough for Shiro to support it...

/Bengt

Den tis 20 nov. 2018 kl 10:54 skrev Philip Whitehouse <[hidden email]>:
Okay..

I’m pseudo-coding here but:

Firstly your accessToken is not just your username. It’s also your password. The reason for this is that it’s the secret that authenticates a user. You currently aren’t storing a real username. The IP address isn’t secret - it’s not your password. It’s just a filter.

Tbh the deficiency in Shiro here is that there’s no AuthToken-based Token implementation. That would have encouraged the right solution from the start.

What you want is a config like the following:

accessToken1=accessToken1,publicApi
accessToken2=accessToken2.publicApi

and then separately

[allowedIPs]
accessToken1=ip1,ip2

and then your filter says:

if(!allowedIPs.get(accessToken).contains(ip1) {
   throw new AuthenticationFailedException();
}

What you need to do is implement a Shiro Ini reader that help you do the second bit. There might even be existing IP filters for Shiro out there. A quick search looks promising.

Best,

Philip Whitehouse

On 20 Nov 2018, at 07:38, Bengt Rodehav <[hidden email]> wrote:

Sorry for being unclear. I'll try to explain better.

We have a REST API that partners to us can access. It is a simple http/GET based protocol that returns JSON data. Authentication is being done via a parameter "accessToken" in the URL (https://....?acessToken=123). The access token is similar to a user. We don't require a password since the accessToken itself is a random GUID. We do, however, only allow access from known IP addresses (white listing). Generally speaking, this is a public site so the firewall restricts no one. But this API needs to be restricted to known IP addresses.

Currently I have created a filter (I have subclassed AuthenticatingFilter) with my own createToken() method. In that method, I extract the access token and the IP address (either from the ServletRequest's getRemoteAddr() or from the "X-Forwarded-For" header). I then create a UsernamePasswordToken with the access token as the user and the IP address as the password.

The number of users accessing this service is not very high so it is easy to maintain them in the ini file as follows:

[users]
accessToken1=123.123.123.123,publicApi
accessToken2=456.456.456.456,publicApi

...where "publicApi" is the role I require for accessing this service.

This approach is really easy and works but it only allows for one IP address per access token which is a limitation for us. Some customers need to access our service from multiple servers and sometimes from an IP address range.

So I need another solution. One solution is of course to use the firewall for white listing. We do that for a number of other services where we only allow access from our partners. However, in this case the site is public except for this exact call. This makes it hard for us to use our firewall. Also, it would be nice to maintain the access tokens and the IP addresses in one place. Otherwise the risk is very high that the firewall will, after a while, not be synced with the access tokens.

I am very open to other approaches. I just took an easy first route that seemed to work fine - for a while...

/Bengt








Den tis 20 nov. 2018 kl 07:21 skrev armandoxxx <[hidden email]>:
Hey ...

Please explain what would you like to achieve (your use case) .. we will try
to help you how to implement it ;) .. Sorry I'm lost too ...

Regards
Armando



--
Sent from: http://shiro-user.582556.n2.nabble.com/
Reply | Threaded
Open this post in threaded view
|

Re: Multiple passwords

armandoxxx
This post was updated on .
In reply to this post by Philip Whitehouse
Another solution is to completely ignore ini.file for access tokens and read tokens and IPs from another data source (our case database).

we have the same issue: we must give acces to users if they have token and are in allowed IP range.

We did this by implementing custom shiro authenticating filter with corresponding realm

StringToken code
public class StringTokenAuthenticationToken implements AuthenticationToken {


  private String token    = null;
  private String ip         = null;


  public StringTokenAuthenticationToken(final String theTheToken, final String theIp) {
    token    = theTheToken;
    ip        = theIp;
  }

  public String getIp() {
    return ip;
  }

  public void setIp(String ip) {
    this.ip = ip;
  }

  public boolean hasIp() {
    return this.ip != null && !this.ip.isEmpty();
  }

  @Override
  public Object getCredentials() {
    return this.token;
  }

  @Override
  public Object getPrincipal() {
    return this.token;
  }
}



Token filter
public class TokenAuthenticationFilter extends BaseAuthFilter {


  private static final Logger LOG = LoggerFactory.getLogger(TokenAuthenticationFilter.class);

  @Override
  protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
    HttpServletRequest httpRequest = WebUtils.toHttp(request);
    String tokenId = null;
    try {
      tokenId = QueryStringParser.get(httpRequest.getQueryString(), "tokenParamName");
    } catch (Exception e) {
      LOG.error("Unable to parse [dcStringToken]", e);
      return null;
    }
    //is client behind something?
    String ipAddress = httpRequest.getHeader("X-FORWARDED-FOR");
    if (ipAddress == null) {
      ipAddress = request.getRemoteAddr();
    }
    return new StringTokenAuthenticationToken(tokenId, ipAddress);
  }

  @Override
  protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
    AuthenticationToken authenticationToken = this.createToken(request, response);
    if (authenticationToken != null) {
      return this.executeLogin(authenticationToken, request, response);
    }
    return true;
  }
}

Token realm (please note that this is spring-boot-hibernate implementation
@Component
public class TokenRealm extends UsernamePasswordRealm {

    private TokenRepository tokenRepository;

    public TokenRealm(
            final TokenRepository theTokenRepository,
            final PrincipalRepository thePrincipalRepository,
            final CredentialsMatcher theCredentialsMatcher) {
        super(thePrincipalRepository, theCredentialsMatcher);
        this.tokenRepository = theTokenRepository;
        this.setAuthenticationTokenClass(StringTokenAuthenticationToken.class);
    }


    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(final AuthenticationToken theToken) {
        StringTokenAuthenticationToken token = (StringTokenAuthenticationToken) theToken;


        ZonedDateTime now = ZonedDateTime.now();
        Principal user;
        Token userToken = this.tokenRepository.findById(UUID.fromString((String) token.getPrincipal())).orElse(null);
        if (userToken == null) {
            throw new AuthenticationException("User token [" + token.getPrincipal() + "] not found!");
        }
      /*if (!userToken.getName().equals(Token.TokenName.LOGIN.name())) {
        throw new AuthenticationException("Invalid token [" + token.getPrincipal() + "] name [" + userToken.getName() + "] should be [" + Token.TokenName.LOGIN.name() + "]!");
      }*/
        if (now.isAfter(userToken.getExpiryDate())) {
            throw new AuthenticationException("User token [" + token.getPrincipal() + "] expired!");
        }

        if (token.hasIp()) {
            //check IP addresses
            boolean validIp = false;
            List<InetAddress> allowedIps = new LinkedList<>();
            String netMask = userToken.getNetMask();
            if (netMask != null && !netMask.isEmpty()) {
                String[] netIps = netMask.split("\\n");
                for (String ip : netIps) {
                    try {
                        if (NetUtils.validateIP(token.getIp(), ip)) {
                            validIp = true;
                            break;
                        }
                    } catch (Exception e) {
                        this.log.error("Exception when checking user ip with token IPs", e);
                    }
                }
                if (!validIp) {
                    throw new AuthenticationException("User ip [" + token.getIp() + "] is invalid for token [" + token.getPrincipal() + "]");
                }
            }
        }

        user = userToken.getPrincipal();
        if (user == null) {
            throw new AuthenticationException("User with token [" + token.getPrincipal() + "] not resolved!");
        }
        if (!user.getActive()) {
            throw new AuthenticationException("User with token [" + token.getPrincipal() + "] not active!");
        }
        this.log.info("Found user [{}] with username [{}] from token [{}]", user.getUuid(), token.getPrincipal(), token.getPrincipal());
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getUuid(), token.getPrincipal(), this.getName());
        this.clearCache(authenticationInfo.getPrincipals());
        return authenticationInfo;
    }

}

Regards
Armando
Reply | Threaded
Open this post in threaded view
|

Re: Multiple passwords

Bengt Rodehav
Hello Armando,

That sounds really interesting - it sounds like we have the same requirements. Can you give some more detail about your solution? E g what classes do you subclass and what methods do you re-implement? Do you also have some logic for IP range checking (not that trivial I think)?

/Bengt

Den ons 21 nov. 2018 kl 08:35 skrev armandoxxx <[hidden email]>:
Another solution is to completely ignore ini.file for access tokens and read
tokens and IPs from another data source (our case database).

we have the same issue: we must give acces to users if they have token and
are in allowed IP range.

We did this by implementing custom shiro authenticating filter with
corresponding realm

StringToken code



Token filter


Token realm (please note that this is spring-boot-hibernate implementation


Regards
Armando




--
Sent from: http://shiro-user.582556.n2.nabble.com/
Reply | Threaded
Open this post in threaded view
|

Re: Multiple passwords

armandoxxx
This post was updated on .
Explanation of our project security:

Clippitamine security uses Apache Shiro as underlaying security library.
Shiro was used, because it allowed both simple and robust security
requirements.
Clippitamine-Shiro security filter implementations:


cTokenAuthzFilter
Filter checking (in isAccessAllowed() method) if JWT token exists in
Authorization: request header and checks if token is valid.

cRestAuthFilter
Resolves request body for login request details and executes login.

cFormAuthFilter
Resolves login request details from application/x-www-form-urlencoded
parameters and executes login.

cHeaderAuthFilter
Resolved login request details from request headers and executes login.

cTokenAuthFilter
Resolves login request details from request parameter and executes login

cLoginRequiredFilter
Allways redirects to loginRequiredUri

Shiro security filter implementation properties:


How they work together:
*AuthFilter implementations only serve for login purposes. Meaning that
filter chain is executed until one of the filters succedes with login user.
If none of the filters resolves login request, last filter
cLoginRequiredFilter is executed and it always redirects to login required
end point.
*AuthzFilter implementations are used for general checking if user is
allowed or denied access. For exmaple, checks validity of JWT token.

REST API security:
- with JWT

filter chain on endpoint /**

noSessionCreation
cTokenTAuthzFilter
cRestAuthFilter
cFormAuthFilter
cTokenAuthFilter
cLoginRequiredFilter

filter chain on endpoint /loginRequired

anon
noSessionCreation


filter chain on endpoint /invalidCredentials

anon
noSessionCreation



MEDIA API security:
without JWT

endpoinds secured by filters:

cTokenAuthFilter
dcLoginRequiredFilter

----------------------------------------------------------------------------

Here is full code (mind our classes and package names .. change what you
need .. here is the code that works)

StringToken code

package com.clippitamine.security.core.tokens;

import org.apache.shiro.authc.AuthenticationToken;

public class StringTokenAuthenticationToken implements AuthenticationToken {


  private String token    = null;
  private String ip         = null;


  public StringTokenAuthenticationToken(final String theTheToken, final
String theIp) {
    token    = theTheToken;
    ip        = theIp;
  }

  public String getIp() {
    return ip;
  }

  public void setIp(String ip) {
    this.ip = ip;
  }

  public boolean hasIp() {
    return this.ip != null && !this.ip.isEmpty();
  }

  @Override
  public Object getCredentials() {
    return this.token;
  }

  @Override
  public Object getPrincipal() {
    return this.token;
  }
}

Base auth filter
package com.clippitamine.security.core.filters;

import lombok.Data;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;


@Data
abstract public class BaseAuthFilter extends AuthenticatingFilter {


    final Logger log;

    /**
     * URL on failed login request
     **/
    @Value("#{ @environment['clippitamine.security.loginFailUrl'] ?:
\"/invalidCredentials\"}")
    String failUrl;

    /**
     * URL on not logged in request
     **/
    @Value("#{ @environment['clippitamine.security.loginInfoUrl'] ?:
\"/loginInfo\"}")
    String loginInfoUrl;

    /**
     * username param name
     */
    @Value("#{ @environment['clippitamine.security.usernameParam'] ?:
\"username\"}")
    String usernameParam;

    /**
     * username param name
     */
    @Value("#{ @environment['clippitamine.security.passwordParam'] ?:
\"password\"}")
    String passwordParam;


    public BaseAuthFilter()
    {
        this.log = LoggerFactory.getLogger(RestAuthFilter.class);
    }


    protected boolean executeLogin(AuthenticationToken token, ServletRequest
request, ServletResponse response) throws Exception {
        if (token == null) {
            String msg = "createToken method implementation returned null. A
valid non-null AuthenticationToken " +
                    "must be created in order to execute a login attempt.";
            throw new IllegalStateException(msg);
        }
        this.log.info("Executing login for [{}]", token.getPrincipal());
        try {
            Subject subject = getSubject(request, response);
            subject.login(token);
            this.log.info("Login success for [{}]", token.getPrincipal());
            return onLoginSuccess(token, subject, request, response);
        } catch (AuthenticationException e) {
            this.log.error("Cannot login user [{}] ", token.getPrincipal(),
e);
            return onLoginFailure(token, e, request, response);
        }
    }


    @Override
    protected boolean onLoginFailure(AuthenticationToken token,
AuthenticationException e, ServletRequest request, ServletResponse response)
{
        try {
            WebUtils.issueRedirect(request, response, this.failUrl);
        } catch (IOException ex) {
            this.log.error("Error while redirecting to [{}]", this.failUrl,
ex);
        }
        return false;
    }


    abstract protected AuthenticationToken createToken(ServletRequest
request, ServletResponse response);
}


Token filter

import com.clippitamine.base.utils.QueryStringParser;
import com.clippitamine.security.core.tokens.StringTokenAuthenticationToken;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;


public class TokenAuthenticationFilter extends BaseAuthFilter {


  private static final Logger LOG =
LoggerFactory.getLogger(TokenAuthenticationFilter.class);

  @Override
  protected AuthenticationToken createToken(ServletRequest request,
ServletResponse response) {
    HttpServletRequest httpRequest = WebUtils.toHttp(request);
    String tokenId = null;
    try {
      tokenId = QueryStringParser.get(httpRequest.getQueryString(),
"tokenParamName");
    } catch (Exception e) {
      LOG.error("Unable to parse [dcStringToken]", e);
      return null;
    }
    //is client behind something?
    String ipAddress = httpRequest.getHeader("X-FORWARDED-FOR");
    if (ipAddress == null) {
      ipAddress = request.getRemoteAddr();
    }
    return new StringTokenAuthenticationToken(tokenId, ipAddress);
  }

  @Override
  protected boolean onAccessDenied(ServletRequest request, ServletResponse
response) throws Exception {
    AuthenticationToken authenticationToken = this.createToken(request,
response);
    if (authenticationToken != null) {
      return this.executeLogin(authenticationToken, request, response);
    }
    return true;
  }
}

Token realm (please note that this is spring-boot-hibernate implementation


package com.clippitamine.security.hibernate.realms.auth;

/*
 * Apache License, Version 2.0
 *
 * Copyright (c) 2011, Dropchop
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import com.clippitamine.base.utils.NetUtils;
import com.clippitamine.entities.core.security.Principal;
import com.clippitamine.entities.core.security.Token;
import com.clippitamine.repositories.db.security.PrincipalRepository;
import com.clippitamine.repositories.db.security.TokenRepository;
import com.clippitamine.security.core.tokens.StringTokenAuthenticationToken;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.springframework.stereotype.Component;
import org.apache.shiro.realm.AuthenticatingRealm;

import java.net.InetAddress;
import java.time.ZonedDateTime;
import java.util.*;

@Component
public class TokenRealm extends AuthenticatingRealm {

    private TokenRepository tokenRepository;

    public TokenRealm(
            final TokenRepository theTokenRepository,
            final PrincipalRepository thePrincipalRepository,
            final CredentialsMatcher theCredentialsMatcher) {
        super(thePrincipalRepository, theCredentialsMatcher);
        this.tokenRepository = theTokenRepository;
       
this.setAuthenticationTokenClass(StringTokenAuthenticationToken.class);
    }


    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(final
AuthenticationToken theToken) {
        StringTokenAuthenticationToken token =
(StringTokenAuthenticationToken) theToken;


        ZonedDateTime now = ZonedDateTime.now();
        Principal user;
        Token userToken =
this.tokenRepository.findById(UUID.fromString((String)
token.getPrincipal())).orElse(null);
        if (userToken == null) {
            throw new AuthenticationException("User token [" +
token.getPrincipal() + "] not found!");
        }
      /*if (!userToken.getName().equals(Token.TokenName.LOGIN.name())) {
        throw new AuthenticationException("Invalid token [" +
token.getPrincipal() + "] name [" + userToken.getName() + "] should be [" +
Token.TokenName.LOGIN.name() + "]!");
      }*/
        if (now.isAfter(userToken.getExpiryDate())) {
            throw new AuthenticationException("User token [" +
token.getPrincipal() + "] expired!");
        }

        if (token.hasIp()) {
            //check IP addresses
            boolean validIp = false;
            List<InetAddress> allowedIps = new LinkedList<>();
            String netMask = userToken.getNetMask();
            if (netMask != null && !netMask.isEmpty()) {
                String[] netIps = netMask.split("\\n");
                for (String ip : netIps) {
                    try {
                        if (NetUtils.validateIP(token.getIp(), ip)) {
                            validIp = true;
                            break;
                        }
                    } catch (Exception e) {
                        this.log.error("Exception when checking user ip with
token IPs", e);
                    }
                }
                if (!validIp) {
                    throw new AuthenticationException("User ip [" +
token.getIp() + "] is invalid for token [" + token.getPrincipal() + "]");
                }
            }
        }

        user = userToken.getPrincipal();
        if (user == null) {
            throw new AuthenticationException("User with token [" +
token.getPrincipal() + "] not resolved!");
        }
        if (!user.getActive()) {
            throw new AuthenticationException("User with token [" +
token.getPrincipal() + "] not active!");
        }
        this.log.info("Found user [{}] with username [{}] from token [{}]",
user.getUuid(), token.getPrincipal(), token.getPrincipal());
        SimpleAuthenticationInfo authenticationInfo = new
SimpleAuthenticationInfo(user.getUuid(), token.getPrincipal(),
this.getName());
        this.clearCache(authenticationInfo.getPrincipals());
        return authenticationInfo;
    }

}

Regards
Armando



--
Sent from: http://shiro-user.582556.n2.nabble.com/
Reply | Threaded
Open this post in threaded view
|

Re: Multiple passwords

Bengt Rodehav
Thanks a million for your reply!

Lots of information for me to take this a step further.

/Bengt

Den tors 22 nov. 2018 kl 09:22 skrev armandoxxx <[hidden email]>:
Explanation of our project security:

Clippitamine security uses Apache Shiro as underlaying security library.
Shiro was used, because it allowed both simple and robust security
requirements.
Clippitamine-Shiro security filter implementations:


cTokenAuthzFilter
Filter checking (in isAccessAllowed() method) if JWT token exists in
Authorization: request header and checks if token is valid.

cRestAuthFilter
Resolves request body for login request details and executes login.

cFormAuthFilter
Resolves login request details from application/x-www-form-urlencoded
parameters and executes login.

cHeaderAuthFilter
Resolved login request details from request headers and executes login.

cTokenAuthFilter
Resolves login request details from request parameter and executes login

cLoginRequiredFilter
Allways redirects to loginRequiredUri

Shiro security filter implementation properties:


How they work together:
*AuthFilter implementations only serve for login purposes. Meaning that
filter chain is executed until one of the filters succedes with login user.
If none of the filters resolves login request, last filter
cLoginRequiredFilter is executed and it always redirects to login required
end point.
*AuthzFilter implementations are used for general checking if user is
allowed or denied access. For exmaple, checks validity of JWT token.

REST API security:
- with JWT

filter chain on endpoint /**

noSessionCreation
cTokenTAuthzFilter
cRestAuthFilter
cFormAuthFilter
cTokenAuthFilter
cLoginRequiredFilter

filter chain on endpoint /loginRequired

anon
noSessionCreation


filter chain on endpoint /invalidCredentials

anon
noSessionCreation



MEDIA API security:
without JWT

endpoinds secured by filters:

cTokenAuthFilter
dcLoginRequiredFilter

----------------------------------------------------------------------------

Here is full code (mind our classes and package names .. change what you
need .. here is the code that works)

StringToken code

package com.clippitamine.security.core.tokens;

import org.apache.shiro.authc.AuthenticationToken;

public class StringTokenAuthenticationToken implements AuthenticationToken {


  private String token    = null;
  private String ip         = null;


  public StringTokenAuthenticationToken(final String theTheToken, final
String theIp) {
    token    = theTheToken;
    ip        = theIp;
  }

  public String getIp() {
    return ip;
  }

  public void setIp(String ip) {
    this.ip = ip;
  }

  public boolean hasIp() {
    return this.ip != null && !this.ip.isEmpty();
  }

  @Override
  public Object getCredentials() {
    return this.token;
  }

  @Override
  public Object getPrincipal() {
    return this.token;
  }
}

Base auth filter
package com.clippitamine.security.core.filters;

import lombok.Data;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;


@Data
abstract public class BaseAuthFilter extends AuthenticatingFilter {


    final Logger log;

    /**
     * URL on failed login request
     **/
    @Value("#{ @environment['clippitamine.security.loginFailUrl'] ?:
\"/invalidCredentials\"}")
    String failUrl;

    /**
     * URL on not logged in request
     **/
    @Value("#{ @environment['clippitamine.security.loginInfoUrl'] ?:
\"/loginInfo\"}")
    String loginInfoUrl;

    /**
     * username param name
     */
    @Value("#{ @environment['clippitamine.security.usernameParam'] ?:
\"username\"}")
    String usernameParam;

    /**
     * username param name
     */
    @Value("#{ @environment['clippitamine.security.passwordParam'] ?:
\"password\"}")
    String passwordParam;


    public BaseAuthFilter()
    {
        this.log = LoggerFactory.getLogger(RestAuthFilter.class);
    }


    protected boolean executeLogin(AuthenticationToken token, ServletRequest
request, ServletResponse response) throws Exception {
        if (token == null) {
            String msg = "createToken method implementation returned null. A
valid non-null AuthenticationToken " +
                    "must be created in order to execute a login attempt.";
            throw new IllegalStateException(msg);
        }
        this.log.info("Executing login for [{}]", token.getPrincipal());
        try {
            Subject subject = getSubject(request, response);
            subject.login(token);
            this.log.info("Login success for [{}]", token.getPrincipal());
            return onLoginSuccess(token, subject, request, response);
        } catch (AuthenticationException e) {
            this.log.error("Cannot login user [{}] ", token.getPrincipal(),
e);
            return onLoginFailure(token, e, request, response);
        }
    }


    @Override
    protected boolean onLoginFailure(AuthenticationToken token,
AuthenticationException e, ServletRequest request, ServletResponse response)
{
        try {
            WebUtils.issueRedirect(request, response, this.failUrl);
        } catch (IOException ex) {
            this.log.error("Error while redirecting to [{}]", this.failUrl,
ex);
        }
        return false;
    }


    abstract protected AuthenticationToken createToken(ServletRequest
request, ServletResponse response);
}


Token filter

import com.clippitamine.base.utils.QueryStringParser;
import com.clippitamine.security.core.tokens.StringTokenAuthenticationToken;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;


public class TokenAuthenticationFilter extends BaseAuthFilter {


  private static final Logger LOG =
LoggerFactory.getLogger(TokenAuthenticationFilter.class);

  @Override
  protected AuthenticationToken createToken(ServletRequest request,
ServletResponse response) {
    HttpServletRequest httpRequest = WebUtils.toHttp(request);
    String tokenId = null;
    try {
      tokenId = QueryStringParser.get(httpRequest.getQueryString(),
"tokenParamName");
    } catch (Exception e) {
      LOG.error("Unable to parse [dcStringToken]", e);
      return null;
    }
    //is client behind something?
    String ipAddress = httpRequest.getHeader("X-FORWARDED-FOR");
    if (ipAddress == null) {
      ipAddress = request.getRemoteAddr();
    }
    return new StringTokenAuthenticationToken(tokenId, ipAddress);
  }

  @Override
  protected boolean onAccessDenied(ServletRequest request, ServletResponse
response) throws Exception {
    AuthenticationToken authenticationToken = this.createToken(request,
response);
    if (authenticationToken != null) {
      return this.executeLogin(authenticationToken, request, response);
    }
    return true;
  }
}

Token realm (please note that this is spring-boot-hibernate implementation


package com.clippitamine.security.hibernate.realms.auth;

/*
 * Apache License, Version 2.0
 *
 * Copyright (c) 2011, Dropchop
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import com.clippitamine.base.utils.NetUtils;
import com.clippitamine.entities.core.security.Principal;
import com.clippitamine.entities.core.security.Token;
import com.clippitamine.repositories.db.security.PrincipalRepository;
import com.clippitamine.repositories.db.security.TokenRepository;
import com.clippitamine.security.core.tokens.StringTokenAuthenticationToken;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.springframework.stereotype.Component;

import java.net.InetAddress;
import java.time.ZonedDateTime;
import java.util.*;

@Component
public class TokenRealm extends UsernamePasswordRealm {

    private TokenRepository tokenRepository;

    public TokenRealm(
            final TokenRepository theTokenRepository,
            final PrincipalRepository thePrincipalRepository,
            final CredentialsMatcher theCredentialsMatcher) {
        super(thePrincipalRepository, theCredentialsMatcher);
        this.tokenRepository = theTokenRepository;

this.setAuthenticationTokenClass(StringTokenAuthenticationToken.class);
    }


    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(final
AuthenticationToken theToken) {
        StringTokenAuthenticationToken token =
(StringTokenAuthenticationToken) theToken;


        ZonedDateTime now = ZonedDateTime.now();
        Principal user;
        Token userToken =
this.tokenRepository.findById(UUID.fromString((String)
token.getPrincipal())).orElse(null);
        if (userToken == null) {
            throw new AuthenticationException("User token [" +
token.getPrincipal() + "] not found!");
        }
      /*if (!userToken.getName().equals(Token.TokenName.LOGIN.name())) {
        throw new AuthenticationException("Invalid token [" +
token.getPrincipal() + "] name [" + userToken.getName() + "] should be [" +
Token.TokenName.LOGIN.name() + "]!");
      }*/
        if (now.isAfter(userToken.getExpiryDate())) {
            throw new AuthenticationException("User token [" +
token.getPrincipal() + "] expired!");
        }

        if (token.hasIp()) {
            //check IP addresses
            boolean validIp = false;
            List<InetAddress> allowedIps = new LinkedList<>();
            String netMask = userToken.getNetMask();
            if (netMask != null && !netMask.isEmpty()) {
                String[] netIps = netMask.split("\\n");
                for (String ip : netIps) {
                    try {
                        if (NetUtils.validateIP(token.getIp(), ip)) {
                            validIp = true;
                            break;
                        }
                    } catch (Exception e) {
                        this.log.error("Exception when checking user ip with
token IPs", e);
                    }
                }
                if (!validIp) {
                    throw new AuthenticationException("User ip [" +
token.getIp() + "] is invalid for token [" + token.getPrincipal() + "]");
                }
            }
        }

        user = userToken.getPrincipal();
        if (user == null) {
            throw new AuthenticationException("User with token [" +
token.getPrincipal() + "] not resolved!");
        }
        if (!user.getActive()) {
            throw new AuthenticationException("User with token [" +
token.getPrincipal() + "] not active!");
        }
        this.log.info("Found user [{}] with username [{}] from token [{}]",
user.getUuid(), token.getPrincipal(), token.getPrincipal());
        SimpleAuthenticationInfo authenticationInfo = new
SimpleAuthenticationInfo(user.getUuid(), token.getPrincipal(),
this.getName());
        this.clearCache(authenticationInfo.getPrincipals());
        return authenticationInfo;
    }

}

Regards
Armando



--
Sent from: http://shiro-user.582556.n2.nabble.com/
Reply | Threaded
Open this post in threaded view
|

Re: Multiple passwords

armandoxxx
no problem ...

best practices when implementing shiro security

1. your custom implementation of Authenticating shiro filter has its own
auth token and it's own realm
2 your custom implementation of AccessControll shiro filter should check if
access for request is allowed
3. mind the filter chain order: (first check if authorizedm, then try to
login user .. if everything else fails = access forbidden)
 - authz filter 1 ... n
 - auth filter 1 .. n
  - AccessForbiddenFilter always throwing 403 FORBIDDEN

thats it ;)

Regards

Armando



--
Sent from: http://shiro-user.582556.n2.nabble.com/