I am getting a ResourceResolver Object from ResourceResolverFactory i.e. I am creating this resourceResolver and I am adapting to Session.
Session session = resourceResolver.adaptTo(Session.class);
Do I need to close both, the resolver and the session or closing one would be suffice?
finally {
if (session != null && session.isLive()) {
session.logout();
}
if (resourceResolver != null && resourceResolver.isLive()) {
resourceResolver.close();
}
}
This question is about "should we be closing both" and not which to close first
The ResourceResolver will close the underlying Session when you call the ResourceResolver.close() method.
If you use newer versions of Sling I would advise you to use the try-with-resource construct when you use ResourceResolver:
try (final ResourceResolver resolver = this.getResourceResolver()) {
[... use resolver here ...]
}
Since ResourceResolver implements the AutoClosable interface it can be used with try-with-resource. This will always close the ResourceResolver and you will not have to deal with exceptions etc.
Beware that you can only do this with ResourceResolvers that you created. If you use the ResourceResolver that you get from a Resource for example you should not close it. It is considered best practice that only the one who created the ResourceResolver should close it.
Closing one will close them both. If you log a message or debug, you will see you don't enter that second if statement.
Related
I use shiro and jwt and try to realize a stateless web application.
When i extend AuthorizingRealm, do i need to executeLogin every request?
Here is my executeLogin method:
public static boolean executeLogin(ServletRequest request) {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String authorization = httpServletRequest.getHeader("Authorization");
if (authorization == null || "".equals(authorization.trim())) {
throw RequestException.fail("未含授权标示,禁止访问");
}
JwtToken token = new JwtToken(authorization, null, null);
// 提交给realm进行登入,如果错误他会抛出异常并被捕获
Subject subject = SecurityUtils.getSubject();
try {
subject.login(token);
} catch (DisabledAccountException e) {
if (e.getMessage().equals("verifyFail")) {
throw new RequestException(ResponseCode.NOT_SING_IN.code, "身份已过期,请重新登录", e);
}
throw new RequestException(ResponseCode.SIGN_IN_INPUT_FAIL.code, e.getMessage(), e);
} catch (Exception e) {
e.printStackTrace();
throw new RequestException(ResponseCode.SIGN_IN_FAIL, e);
}
// 如果没有抛出异常则代表登入成功,返回true
return true;
}
By Stateless means that each request does not depend from the previous, however this does not mean that Shiro does not use sessions.
When the user does a successful login Shiro attaches to the HTTPResponse some cookies. When the client sends the cookies to each further request, Shiro automatically extracts the Subject (associates the cookies with the user) so, in your code, you can immediately call SecurityUtils.getSubject().
A realm is the wrong approch here as it usually have by definition a 1-to-1 correlation with a data source. What you actually want to do is to controll access to your servers resources, verifying a JWT from a client. This can be done by a AccessControlFilter, reading the authorization header and verifing its claims in the filters isAccessAllowed method. The methods return value defines wheather access is allowed or not.
You don't need to login a subject at all since the AccessControlFilter decides wheather access is granted or denied, either forwarding the user to the requested resource or redirecting a 401 - Unauthorized response.
Yes, you should log in for each request. This will attach the subject to the current thread and allow you to use features: like use annotations for authz.
As you are using stateless call, you have to login each time and generate new subject and also load authorization details with appropriate realm.
The another option you could try is, put subject in cache (ehCache) once successful login and then on every request you can get subject from Cache and use for authorization. This will avoid login and authorization object population on every request. But you have to make sure to remove object from cache on logout event.
Similar thing has been already done by one user at:
https://github.com/jikechenhao/springmvc-shiro-react-redux-restful-example
Currently using grails 2.2.2
I've been trying to implement tokens into my application and have come up with this issue. We try to avoid re-rendering pages because it can be very slow so we return JSON instead. The following is a basic controller call that we use but I'm not sure what I should be doing to reset/get a new token.
public saveThing(ThingCommand cmd) {
Map model = [:]
withForm {
try {
thingService.saveThing(cmd)
model.success = true
} catch (Exception e) {
model.error = true //any validation errors or anything else
// RESET TOKEN HERE/GET NEW TOKEN?
}
}.invalidToken {
model.invalidToken = true
}
render model as JSON
}
From my understanding the token is thrown away once the withForm closure is executed. This causes an issue since I don't actually re-render the form which seems to be the normal way of generating a new token. How could I do this manually or is there an easier way to do this (plugin?)
Thanks!
Form tokens through withForm are not designed to be used with AJAX requests. They are designed to be used with HTML forms and POST requests which re-render the form and generate a new token for the form.
In order to make them work with JSON/AJAX requests you will need to implement your own token generation when you process the request and reject it. A good starting place would be to look at the old tests which test withForm. This should give you an idea on how tokens are created and stored.
I have a ServletFilter (which happens to be a GuiceShiroFilter) that processes incoming web requests before they go to a Jersey 1.x Resource.
However, in some situations (namely when Shiro finds that the request is not authenticated), I want to change which Jersey resource answers my request, without the resource that otherwise would have answered even being able to respond.
Here's what I have (in my Shiro AuthenticatingFilter.onLoginFailure()):
ServletRequest request = ...;
RequestDispatcher disp = request.getRequestDispatcher("/resource/that/always/responsds/with/a/403");
try {
disp.forward(request, response);
} catch (ServletException | IOException e) {
e.printStackTrace();
}
// this is needed to prevent the woud-be resource from responding as well
return false;
The problem of this server-side redirect is that not returning false will invoke both my resource for "/resource/that/always/responsds/with/a/403" and the original would-be response, and in the best case the response body contains both responses concatenated.
Is there a way to modify an existing instance of (Http)ServletRequest from a Filter such that later on, only the redirected-to resource can answer?
I dug into the issue a little bit and I realized that there is little I can do here, given that I don't control how the filter chain is processed further.
In a generic Filter, the implementer can wrap the current ServletRequest (in doFilter() in a HttpServletRequestWrapper implementation. This wrapper can then override the request URI. However, this requires that the implementer has control over how the filter chain is continued (which is where the wrapped request can be fed back into the execution path), but this is not the case in my situation, where Shiro controls that.
With Shiro, the filter chain continuation is controlled in AdviceFilter.doFilterInternal(), many layers above my own AuthenticatingFilter implementation.
So for now, my best bet is to do what I already described above: Invoke another resource - free from filters - by using a RequestDispatcher and stop the filter chain by returning false at the end of my AuthenticatingFilter's onLoginFailure()
In our SharePoint application we have used the UnitOfWork + Repository patterns together with Entity Framework. To avoid the usage of the passthrough authentication we have developed a piece of code that impersonate a single user before creating the ObjectContext instance in a similar way that is described in "Impersonating user with Entity Framework" on this site.
The only difference between our code and the referred question is that, to do the impersonation, we are using RunWithElevatedPrivileges to impersonate the Application Pool identity as in the following sample.
SPSecurity.RunWithElevatedPrivileges(delegate() {
using (SPSite site = new SPSite(url)) {
_context = new MyDataContext(ConfigSingleton.GetInstance().ConnectionString);
}
});
We have done this way because we expected that creating the ObjectContext after impersonation and, due to the fact that Repositories are receiving the impersonated ObjectContext would solve our requirement.
Unfortunately it's not so easy. In fact we experienced that, even if the ObjectContext is created before and under impersonation circumstances, the real connection is made just before executing the query, and so does not use impersonation, which break our requirement.
I have checked the ObjectContext class to see if there was any event through which we can inject the impersonation but unfortunately found nothing.
Any help?
We had a simillar problem when we used LinqToSharePoint. The DataContext is created from the HttpContext.Current and did not consider the RunWithElevatedPrivileges method. We did a nasty workaround that we backed up the original HttpContext, created a new dummy HttpContext in the RunWithElevatedPrivileges method and the problem went away. Obviously we set the context to the original afterwards.
Edit:
You can use the method below to create new dummy HttpContext.Call this method as first in your RunWithElevatedPrivileges. In the normal context just backup your currenct context with var backupContext = HttpContext.Current and after everything is done just set the context back.
private void SetNewContextWeb(SPWeb oWeb)
{
HttpRequest httpRequest = new HttpRequest(string.Empty, oWeb.Url, string.Empty);
HttpContext.Current = new HttpContext(httpRequest, new HttpResponse(new System.IO.StringWriter()));
SPControl.SetContextWeb(HttpContext.Current, oWeb);
}
I've disabled sessionState in my mvc2 app via the web.config and also created my own controllerfactory and dummy tempdata provider, as described here:
How can I disable session state in ASP.NET MVC?
Only I've made it so that SaveTempData throws an exception:
public void SaveTempData(ControllerContext controllerContext,
IDictionary<string, object> values)
{
throw new NotImplementedException(
"Cannot set tempdata, no session state is available.");
}
I've made sure that no code is ever using either the Session or the TempData objects, but I still see this exception getting thrown after the "OnResultExecuted" event has been raised. I used to use this very same pattern on my mvc1 site and never saw the exception. Any ideas?
If I change my "SaveTempData" implementation to this:
public void SaveTempData(ControllerContext controllerContext,
IDictionary<string, object> values)
{
if (values.Count != 0)
{
throw new NotImplementedException(
"Cannot set tempdata, no session state is available.");
}
}
Everything works as expected - I'm just hoping to learn why SaveTempData is called at all when I'm not using it anywhere.
Update
Discovered this article: http://www.gregshackles.com/2010/07/asp-net-mvc-do-you-know-where-your-tempdata-is/
Which explains that ExecuteCore calls PossiblyLoadTempData and PossiblySaveTempData around an action - which is what was causing my issue. Is this a new addition in mvc2 vs. mvc1?
That's how it is implemented in the Controller.ExecuteCore method. The LoadTempData and SaveTempData methods will always be called before and after each action so make sure that they do not throw an exception. In order to disable the session effectively I would recommend you putting the following in your web.config:
<sessionState mode="Off" />
Discovered this article: http://www.gregshackles.com/2010/07/asp-net-mvc-do-you-know-where-your-tempdata-is/
Which explains that ExecuteCore calls PossiblyLoadTempData and PossiblySaveTempData around an action - which is what was causing my issue. Is this a new addition in mvc2 vs. mvc1?