how to share the token between classes - session

I have having a design issue with asp.net web-api and would like to know how to solve this problem
public abstract class BaseApiController<TEntity> : ApiController where TEntity : Entity
{
protected string GetUsername()
{
return Utilities.GetUsername(Request.Headers.Authorization);
}
//some other code
}
public class StakeholderApiController : BaseApiController<Stakeholders>
{
ILogger _logger = new CustomApiLogger("StkhManager", GetUsername())
//some other code
}
now the problem I have is:
I have the BaseApiController which I am using the share certain functionality between all ApiControllers.
And then I have some specified ApiController for certain not shared functionality.
Now while doing logging, I do want to log the logged in user's name, the problem is I have to pass it everytime I create a new instance, is there a way I can make the logged in user's name global for the current api request so that it can be accessed everywhere.
I cannot make it static, otherwise for others request it will give wrong username.
is there a way I can avoid passing it everytime. Given that webapi is stateless, so session cant be used, is there anyother way??
I am using angularjs front end, hence I am NOT using any authorization technique provided by MVC/.net
Note:
I cannot move creation of Logger to base class for certain reasons
This is just one example, I want to use the logged in user's name in many other place. Hence dont want to pass it around.

There is a standard pattern in setting and accessing principal with ASP.NET Web API. From an ApiController such as your BaseApiController, you can just use the User property to retrieve the same. To set it, typically, the HttpRequestContext is obtained from the request object and the principal is set like so.
Request.GetRequestContext().Principal = new ClaimsPrincipal(...);
BTW, you can access the current request object in the Web API pipeline pretty much from anywhere.

Related

RequestMapping discriminating by user in Spring

I have two controllers that handle the same resource. One for the regular web app and another one for portals (and in theory there could be more than one portal and more controllers).
#Controller
#RequestMapping(value = "/*/web/cases")
public class CasesDetailController extends BaseController<CasesForm> { ... }
#Controller
#RequestMapping(value = "/*/portal/cases")
public class CasesPortalDetailController extends BaseController<CasesForm> { ... }
In some controllers we just resolve a different view for the portal, but for some cases the controller logic is quite different. For example this one has many mappings in the portal that are not available in the app.
The problem comes with managing 2 different urls for the same resource. For example, if I wanna place a link for a case I have to calculate it in the server by checking if the current user is logged in the web or the portal instead of placing a constant base url and an uuid as parameter.
My question is if I can do something about the request mapping to decide which controller can I use. The best I can think of is using a parameter:
#RequestMapping(value = "/*/cases") // Web
#RequestMapping(value = "/*/cases", params = "device=portal") // Portal
But I would like to avoid sending that info in the url when I have it available in the user (we use a custom user class that extends the base user from spring and it contains the device). Is there any way to check that in the request mapping? Something like this:
#RequestMapping(value = "/*/cases", magicFunctionality=getLoggedUser().getDevice()="web")
Probably nothing like this exists (at least I found nothing in the manual) but any ideas of how to face this problem would be wellcome.
Thanks in advance.
Gonzalo.

Spring calling controller method based on user information

Suppose there are two type of roles in the application -
Admin
Zonal Manager
Admins can get all the office ids while the zonal managers can get only the office assigned under his zone. In the controller I want something like this
#RequestMapping(method = RequestMethod.GET)
Collection<Long> getOfficeIds(){
// returns all office ids in system
}
#RequestMapping(method = RequestMethod.GET, value = "/{zoneId}")
Collection<Long> getOfficeIds(#RequestParam("zoneId") long zoneId){
// returns all office ids in the zone
}
Now I want all my users to make request with the no-arg version only (the first method). The system should get user role before hitting controller and should call appropriate controller method (if admin then call the first method, if zonal manager call the second one with appropriate zone).
The question is , is it possible at all ? If yes then what would be the best way of doing this ? I could try to modify the request in a servlet filter. Is there a way using method argument resolver ?
Per comments, I am posting the answer below.
The best thing to do to achieve your goal is to add a filter which runs before the request is handled by the controller. In this filter, you can apply the appropriate logic to determine the requesting user's role and act accordingly. If you follow the same URL pattern in all of your controllers to handle these different cases, you can simply rewrite the internal URL after determining which case to apply so that it can be handled by the appropriate controller. In this way, you can keep all of your user-role logic in one location and your controller logic can handle their own, separate flows accordingly.
To create such a filter using spring, you may do something like the following:
#Component("accountContextFilter") public class AccountContextFilter extends OncePerRequestFilter {
public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException{
//user role and routing logic
}
}
The reference for the logic inside doFilterInternal can be found here: How to use a servlet filter in Java to change an incoming servlet request url?
Simply change the request path accordingly by appending to your route with the role-defined URLs and you're done.

How to handle authorization with Breeze JS?

Currently my app looks at router parameter and logged in user (Principal.Identity) to authorize access to certain resources (e.g: Add student to your class [identity + class id]). However, If I'm not wrong, breeze js support just one bulk save. It seems to be that I will have to open each and every data and run through the validation/authorization. That is fine,
but what I may lose is nice separation of cross cutting concern out side my business logic (as a message handler) (finding what roles user has on the class) and nice Authroize annotation feature (just say what roles are needed). So do I have to trade off or is there better programming model which Breeze JS might suggest?
Update:
My question is more on how to separate the authorization (find assigned roles in message handler + verify if required roles are present by adding authorize attribute to controller methods) logic from business or data access logic. Without breeze, I will inspect the incoming message and its route parameter to fetch all its roles then in my put/post/delete methods I would annotate with required roles. I cannot use this technique with breeze (its not breeze's limitation, its trade off when you go for bulk save). So wanted to know if there is any programming model or design pattern already used by breeze guys. There is something on breeze's samples which is overriding context and using repository pattern, will follow that for now.
Breeze can have as many 'save' endpoints as you want. For example, a hypothetical server implementation might be
[BreezeController]
public class MyController : ApiController {
[HttpPost]
[Authorize(...)]
public SaveResult SaveCustomersAndOrders(JObject saveBundle) {
// CheckCustomersAndOrders would be a custom method that validates your data
ContextProvider.BeforeSaveEntitiesDelegate = CheckCustomerAndOrders;
return ContextProvider.SaveChanges(saveBundle);
}
[HttpPost]
[Authorize]
public SaveResult SaveSuppliersAndProducts(JObject saveBundle) {
...
}
You would call these endpoints like this
var so = new SaveOptions({ resourceName: "SaveWithFreight2", tag: "freight update" });
myEntityManager.saveChanges(customerAndOrderEntities, {
resourceName: "SaveCustomersAndOrder" }
).then(...)
or
myEntityManager.saveChanges(supplierAndProductEntities, {
resourceName: "SaveSuppliersAndProducts" }
).then(...)
Authorization is mediated via the [Authorize] attribute on each of the [HttpPost] methods. You can read more about the [Authorize] attribute here:
http://sixgun.wordpress.com/2012/02/29/asp-net-web-api-basic-authentication/
The proper way to do this IMHO is to separate the endpoint authorization and the database actions authorization.
First, create an entity that manages the grands per controller/method and role. For each method you have a value allowed - not allowed for the specific role. You create a special attribute (subclass of Authorize) that you apply to your controllers (breeze or plain web api) that reads the data and decides whether the specific endpoint can be called for the user/role. Otherwise it throws the Unauthorized exception.
On the breeze side (client) you extend the default adapter settings with a method that adds the authentication headers from identity that you received at login, something like this :
var origAjaxCtor = breeze.config.getAdapterInstance('ajax');
$.extend(true, origAjaxCtor.defaultSettings, Security.getAuthenticationHeaders());
On the server, add a second entity that manages the authorization for the CRUD operations. You need a table like (EntityName, AllowInsert, AllowUpdate, AllowDelete). Add a BeforeSave event on the Context Manager or on the ORM (EF or something else) that loops all entities and applies the policy specified on the table above.
This way you have a clear separation of the endpoint logic from the backend CRUD logic.
In all cases the authorization logic should first be implemented server side and if needed should be pushed to the clients.
The way breeze is implemented and with the above design you should not need more than 1 save endpoint.
Hope it helps.
However, If I'm not wrong, breeze js support just one bulk save.
That is entirely wrong. You have free reign to create your own save methods. Read the docs, it's all there.

How to map a path to multiple controllers?

I'm currently working on a spring based web application and have a special requirement that seems not (at least not out of the box) be provided by spring MVC. The application serves data for multiple users each organized in their own "company". Once a user has logged in, I'm able to identify to which company he belongs to.
The application itself is built with multiple "modules", each with it's own domain objects, DAO, Service and Controller classes. The idea behind this concept is that I can for example extend a certain controller class (let's say to use a different service class) based upon the user and here is my problem.
Since i do not want to change my request paths for certain users, I'm currently looking for a way how to serve a request issued on a certain request path with different instances of a controller based upon the user issuing the request.
I came up with the idea to attach a HTTP Header Field for the company
Example:
X-Company:12345
and have my controllers configured like this:
#Controller
#RequestMapping(value="/foo/")
public class FooController {
// ...
}
#Controller
#RequestMapping(value="/foo" headers="X-Company=12345")
public class SpecialFooController extends FooController {
// ...
}
However this is not possible, since spring MVC treats each header (except Content-Type and Accept) as a kind of restriction, so in my case it would handle all requests with the FooController instead of the SpecialFooController unless i add a "headers" restriction on the FooController as well, which is not practicable.
Is there some way how to customize this behaviour or some direction one could point me to look for? Or maybe someone has another idea how to achieve this. It'll be highly appreciated.
Thanks!
I'am not sure but I think you can do this with HandlerMapping. Have a look at the documentation
To take your own suggestion, you can use the #RequestHeader annotation in your controller methods:
#Controller
public class MyController {
#RequestMapping("/someAction")
public void myControllerMethod(#RequestHeader('X-Company-Id') String companyId) {
}
}
Or you could use #PathVariable:
#Controller
public class MyController {
#RequestMapping("/{companyId}/someAction")
public void myControllerMethod(#PathVariable("companyId") String companyId) {
}
}
Using this approach would mean that it is in fact different URLs for each company, but if you can set the company id header, I guess you also can suffix the URLs with the company id.
But there are also other possibilities. You could write an interceptor that puts the company id in a session or request variable. Then you wouldn't have to add the annotation to every controller method. You could also use a subdomain for each company, but that wouldn't look too pretty if the company id is a random alphanumeric string. E.g: companyone.mydomain.com, companytwo.mydomain.com
Edit
#RequestMapping can be added to the controller level as you know, so you should be able to do
#Controller
#RequestMapping("/controller/{companyId}")
as the base url, if that's a better option.
I was able to meet the requirement by making usage of a customized RequestCondition. By defining your own annotation that can be placed at the type and method level of a controller. Extending the RequestMappingHandlerMapping by your own implementation and overriding the getCustomTypeCondition() and getCustomMethodCondition() methods translates a controller annotation into your own RequestCondition.
When a request comes in, the custom RequestCondition will be evaluated and the annotated controller(method) will then be called to serve the request. However this has the downside, that one needs to remove a servlet-context.xml file and switch to the WebMvcConfigurationSupport class instead in order to be able to use your customized RequestMappingHandlerMapping class.
This question was also discussed here.
Edit:
A pretty good example using this can be found here.

Passing User Info to MVC Controller

I am looking at various methods to implement Authentication in my MVC3 app. I would like to use my own code to do the authentication – something similar to Is it possible to create a Logon System with ASP.NET MVC but not use the MembershipProvider? (I know that there are other methods.) I would like to know once I authenticate a user using one of these methods, how do I get the user information to the Controller constructor. (By user information I mean username or userID).
One of the options I considered is putting that info into the Session. This works, but it is difficult to test since I get the Session out of the Context which does not exist during the test.
I would appreciate any ideas for how to pass user info to the controller constructor.
No. Do not use Session for authentication. It's less secure, and unstable (sessions can be destroyed at will by the server).
In MVC, you don't need to use membership at all, but.. and I will make a point of emphasizing the but... Doing authentication correctly is not a trivial task. It's very very very easy to get it wrong and not even realize it. Even if you know what you're doing. It's something that should be heavily analyzed, tested, verified, and re-analyzed.
I would suggest, if you don't want to extend this effort, you should probably just use the default providers (there are several you can choose from).
But in any event, if you are determined to do it yourself, all you need is some way to verify the user. MVC does not integrate with the membership provider like WebForms does. It uses it for convenience. If you look in the default AccountController that is generated for you if you create an Internet project, all it does is call Membership.VerifyUser().
The truly important thing is the Authentication cookie system, which MS provides in the form of the FormsAuthentication class. I would VERY strongly recommend using this for the cookie management, unless you REALLY REALLY REALLY know what you are doing.
Just look in the AccountController, and it should be very obvious how this works. FormsAuthentication is the part that integrates into the app and tells asp.net that the user has already been authenticated. It uses a secure, encrypted cookie, and it's well designed (it even allows you to store your own additional data in an encrypted format).
Forms Authentication is a set of classes that work together to provide a transparent authentication mechanism, and is integrated into MVC and Asp.net WebForms. They are basically an implementation of the IPrincipal and IIdentity system, which is integral to asp.net (if you type User.IsAuthenticated this uses the IPrincipal interface).
In my original post I was looking at passing User Info to the Controller constructor. I did not want the Controller to depend on HttpContext, because this would make it difficult to test.
While I thank Mystere Man for his solution, I hope the following alternate solution would help someone. I have a small project (about a dozen controllers) so it is not too bad.
I basically created my custom ControllerFactory inheriting from DefaultControllerFactory:
public class MyCustomControllerFactory : DefaultControllerFactory
{
public MyCustomControllerFactory ()
{
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
return null;
}
else
{
//Example of User Info - Customer ID
string customerIDStr = requestContext.HttpContext.Session["CustomerID"].ToString();
int customerID = Int32.Parse(customerIDStr);
//Now we create each of the Controllers manually
if (controllerType == typeof(MyFirstController))
{
return new MyFirstController(customerID);
}
else if (controllerType == typeof(MySecondController))
{
return new MySecondController(customerID);
}
//Add/Create Controllers similarly
else //For all normal Controllers i.e. with no Arguments
{
return base.GetControllerInstance(requestContext, controllerType);
}
}
}
}
I then set the ControllerFactory in the Global.asax.cs Application_Start() method.
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
ControllerBuilder.Current.SetControllerFactory(new MyCustomControllerFactory ());
}
P.S. I looked into using DI Containers like Ninject, but I think they were too complicated for my current project. I would look at them in a few months when it really makes sense to use them.

Resources