Apache Shiro: Exception-Handling with Multiple Realms - authentication

We are using two realms (one for hashed passwords, the other one for generated plaintext keys) - this is working as expected.
With a single realm, we could throw a DisabledAccountException exception in our realm's protected AuthenticationInfo doGetAuthenticationInfo(final AuthenticationToken authToken) and explicitly catch such an exception in our application.
Now that we have two realms, all exceptions are Shiro-internally caught; so if one realm fails, the second one can be tried as well. However, this kind of redirect will only throw generic AuthenticationExceptions to our application.
Is there any workaround with multiple realms so that we can have more specific exceptions (to know if an account is locked, the credentials are simply wrong,...)?

You need to specify your own AuthenticationStrategy in your ModularRealmAuthenticator.
The ModularRealmAuthenticator uses AtLeastOneSuccessfulStrategy by default and AtLeastOneSuccessfulStrategy ignores the exceptions and keeps trying to login the users using all the realms available.
We had a similar scenario on the tynamo project and to workaround this issue I've implemented my own AuthenticationStrategy, called FirstExceptionStrategy, that works with multiple realms and throws the first exception it gets. This approach works fine as long as there is only one Realm per Token type.
The implementations is rather simple:
/**
* {#link org.apache.shiro.authc.pam.AuthenticationStrategy} implementation that throws the first exception it gets
* and ignores all subsequent realms. If there is no exceptions it works as the {#link FirstSuccessfulStrategy}
*
* WARN: This approach works fine as long as there is ONLY ONE Realm per Token type.
*
*/
public class FirstExceptionStrategy extends FirstSuccessfulStrategy {
#Override
public AuthenticationInfo afterAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo singleRealmInfo, AuthenticationInfo aggregateInfo, Throwable t) throws AuthenticationException {
if ((t != null) && (t instanceof AuthenticationException)) throw (AuthenticationException) t;
return super.afterAttempt(realm, token, singleRealmInfo, aggregateInfo, t);
}
}
I repeat, this only works if there is ONLY ONE Realm per Token type.
For more info about my particular scenario see here: http://jira.codehaus.org/browse/TYNAMO-154

Related

Is There A Generic Way To Search For LDAP Groups With Shiro?

I am using org.apache.shiro.realm.ldap.DefaultLdapRealm to authenticate against LDAP (using ldap://ldap.forumsys.com:389/dc=example,dc=com as an example).
However, when I try to check for Roles it always fails. It turns out that the DefaultLdapRealm returns null when searching for groups.
/**
* Method that should be implemented by subclasses to build an
* {#link AuthorizationInfo} object by querying the LDAP context for the
* specified principal.</p>
*
* #param principals the principals of the Subject whose AuthenticationInfo should be queried from the LDAP server.
* #param ldapContextFactory factory used to retrieve LDAP connections.
* #return an {#link AuthorizationInfo} instance containing information retrieved from the LDAP server.
* #throws NamingException if any LDAP errors occur during the search.
*/
protected AuthorizationInfo queryForAuthorizationInfo(PrincipalCollection principals,
LdapContextFactory ldapContextFactory) throws NamingException {
return null;
}
There is a similar question from 2012, however, it looks like a copy of the code from the ActiveDirectoryRealm.
Does everyone who wants to use LDAP with groups using Shiro have to write a custom Realm?
Couldn't the DefaultLdapRealm take a property that configures the search filter for groups but doesn't require extra code (like the userDNTemplate is used for login)?
Does such a Realm already exist in a maven dependency?
I think the biggest issue is there are many many different ways to store things in LDAP, there is a hand full of common techniques though.
op moved this to a mailing list thread: http://shiro-user.582556.n2.nabble.com/New-LDAP-Realm-Proposal-tp7581200p7581291.html

#Auth Injection in ContainerFilter

I'm using DW 0.9.1 and it would be cool, if I could inject the #Auth XYzObject into some ContainerRequest or even better in a ContainerResponseFilter (or servlet filter).
Does anyone knows if this is possible?
The usecase: Some users does have different allowd access rates (rate limiting), e.g. max. 2 request per second and max 60 per Minute. This can be verified with the injected #Auth XYzObject.
In the end I can do this also in the Ressource, where this information is available, but as I said it would be cool to do this outside of my ressources in a filter or something else. And I do not want to do this is the authenticating/ authorization process, because rate limiting is not related to this. At the moment,all the variants I tried, nothing works, so it seems not possible, but I hope someone knows the trick.
How the #Auth annotation works is that it is handled by a ValueFactoryProvider, which is used only for (resource) method parameter injection. So you can't inject it into arbitrary locations.
However, when you created XyzObject you made it implement java.security.Principal. The reason DW makes you use this type, is because after it authenticates, it sets the Principal in the SecurityContext, as seen in the AuthFilter.
If you look at the implementation for AuthValueFactoryProvider, you will see that the way it obtains the Principal is by getting it from the SecurityContext. And that's how the Principal is injected with #Auth as a method argument.
In a ContainerRequestFilter (and in may other locations), you have access to the SecurityContext. In a filter you can get it with requestContext.getSecurityContext(). So in your filter you can get the Principal from the SecurityContext and just cast it
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
Principal principal = requestContext.getSecurityContext().getUserPrincipal();
if (principal != null) {
XyzObject xyz = (XyzObject)principal;
}
}

ServiceStack implemente CRUD on UserAuth table generated by Authentication

I'm trying the built-in Authentication of ServiceStack. My approach is 'OrmLiteAuthRepository' so users' information are stored in Sql Server instead of the default in memory storage. I use Postman to test the endpoints.
My target is receiving user rows, updating user information, creating users, deleting an user row. Those are the endpoints I found in Postman after importing (I didn't create those endpoints):
GET 'http://localhost:47391/api/register',
PUT 'http://localhost:47391/api/json/reply/Register'
POST 'http://localhost:47391/api/json/reply/Register'
I tested POST, Sql Server automatically created the tables to store user data. And the data could be written into Sql Server so I have no problem with POST.
But with PUT, isn't it for updating the existing row? I append '/{id}' to the end. But it created a new row in the database instead of updating the existing one. How does it work?
With GET, I got no implementation error.
{
"ResponseStatus": {
"ErrorCode": "NotImplementedException",
"Message": "Could not find method named Get(Register) or Any(Register) on Service RegisterService",
"StackTrace": " at ServiceStack.Host.ServiceExec`1.Execute(IRequest request, Object instance, Object requestDto, String requestName)\r\n at ServiceStack.Host.ServiceRequestExec`2.Execute(IRequest requestContext, Object instance, Object request)\r\n at ServiceStack.Host.ServiceController.<>c__DisplayClass11.<>c__DisplayClass13.<RegisterServiceExecutor>b__10(IRequest reqCtx, Object req)\r\n at ServiceStack.Host.ServiceController.ManagedServiceExec(ServiceExecFn serviceExec, IService service, IRequest request, Object requestDto)\r\n at ServiceStack.Host.ServiceController.<>c__DisplayClass11.<RegisterServiceExecutor>b__f(IRequest requestContext, Object dto)\r\n at ServiceStack.Host.ServiceController.Execute(Object requestDto, IRequest req)\r\n at ServiceStack.HostContext.ExecuteService(Object request, IRequest httpReq)\r\n at ServiceStack.Host.RestHandler.GetResponse(IRequest request, Object requestDto)\r\n at ServiceStack.Host.RestHandler.ProcessRequestAsync(IRequest httpReq, IResponse httpRes, String operationName)"
}
}
How to implement it? I assume I consider the user a normal Web Service entity? and create 'UserService', and requests like:
[Route("/register")]
public class User : IReturn<UserResponse>
{
...
}
BUT there isn't a model class like 'User' due to the tables are created by ServiceStack itself, how to solve this?
Or is there something I am not aware of. Thanks.
The error message:
Could not find method named Get(Register) or Any(Register) on Service RegisterService
Is saying you're trying to call the built-in ServiceStack Register Service instead of your Service. But the Register Services isn't enabled by default, your AuthFeature likely explicitly enables it, either with:
Plugins.Add(new RegistrationFeature());
Or on the AuthFeature:
Plugins.Add(new AuthFeature(...) {
IncludeRegistrationService = true
});
If you don't want to enable ServiceStack's built-in Register Service you'll need to remove the registration where it's enabled.
If you instead want the Register Service registered at a different path, you can specify a different route with:
Plugins.Add(new RegistrationFeature {
AtRestPath = "/servicestack-register"
});

Access caller roles in SLSB using Jboss7

I'm using jboss as 7.1.1.Final and have configured a security-domain using LdapExtLoginModule. The login works so far.
I now want to access the roles loaded by the module in an SLSB. I know how to access the username. My example uses ejb 3.1 and prints the username to System.out.
I don't know how to access the roles and didn't find anything in the documentation. The EJBContext provides the method isCallerInRole(String) which proves that the context itself knows the roles but I can not find a method which returns a set of roles.
I know that I could write a custom LoginModule which extends the LdapExtLoginModule and sets a custom principal containing the roles. But maybe there is an easier approach using existing functionality. Does anybody know such approach?
SLSB code:
#Stateless
#Remote(IAService.class)
public class AService implements IAService
{
#Resource
private EJBContext context;
#Override
public void printUserData() {
System.out.println("Name: " + context.getCallerPrincipal().getName());
// TODO print roles
}
}
Nobody answered my question so far and because I finally have a working solution I will now share it with you:
The Java EE API does not provide any methods to access the information in server independent way. So I tried the method of writing a login module which sets a custom principal. As it turns out this does not work either.
Inspired by the answer to this question I now use the following code to get the caller roles:
private Group getRoles() {
final Subject subject = (Subject)PolicyContext.getContext("javax.security.auth.Subject.container");
final Set<Group> groups = subject.getPrincipals(Group.class);
for (final Group group : groups) {
if ("Roles".equals(group.getName())) {
return group;
}
}
throw new IllegalStateException("No roles group found");
}
The Group returned by this method contains Principals which have the names of the users groups. This only works on JBoss whose LoginModules set a Group of name "Roles".

Multitenant/Shared Application system, how to maintain multiple tentant-specific identifiers?

I have a multi-tenant system where each tenant shares the same instance of the codebase, but has their own databases.
I'm using RavenDB for persistence, with a standard c# facade/BLL backend wrapped with Asp.net WebAPI, and I'm finding that at every lower level operation (deep within my business logic classes) that touch the datbase, I need to pass in an identifier so that my RavenDb client session knows which database to operate against.
When the user authenticates, I resolve the appropriate database identifer, store it in the session manager. Every call against the Web API layer passes in a session ID which resolves the database ID in the backend, which is then used to pass into every single facade/BLL call.
All my dependencies are handled via an IoC container at the WebAPI level, but i can't pass in the database ID at this phase because it can be different for every user that is logged in.
this, of course is getting tedious.
can someone give me some guidance as to what I can do to alleviate this? Maybe perhaps some sort of policy injection/AOP solution?
a rough sample of my backend code looks like..
public class WidgetService()
{
private WidgetBLL _widgetBLL;
private ISessionManager _sessionManager;
public WidgetService(WidgetBLL _widgetBLL, ISessionManager sessionManager)
{
_widgetBLL = widgetBLL;
_sessionManager = sessionManager
}
public Widget getWidget(string sessionId, string widgetId)
{
string DbId = sessionManager.ResolveDbId(sessionId)
return _widgetBLL.GetWidget(string dbId, string widgetId);
}
}
public class WidgetManager()
{
public GetWidget(string dbId, string widgetId)
{
using (IDocumentSession session = documentStore.OpenSession(dbId)
{
var widget = session.load<Widget>(widgetid);
}
return widget;
}
}
the DBID is the identifier for that particular tenant that this particular user is a member of.
You need to change how you are using the session.
Instead of opening and closing the session yourself, do that in the IoC code.
Then you pass a session that is already opened for the right db.