I wanted to block some users for accessing some services in JHipster.
How can I authorize a particular user for accession a ReST web Service in JHipster?
For blocking the access on the backend side, use the #Secured annotation on selected methods (rest entry points) in web/rest/*resource.java.
Example:
#RequestMapping(value = "/data-fields",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
#Secured({AuthoritiesConstants.ADMIN})
public List<DataFieldDTO> getAllDataFields() {
log.debug("REST request to get all DataFields");
return dataFieldService.findAll();
}
As Gaël Marziou says, I believe that what you are trying to do is to block it on frontend's part. If it´s the case a possible way to do it is managing the use of "has-authority". For example: has-authority="ROLE_ADMIN"
So what you should do is the opposite, create an authority which allows some users to have access to ReST web Service
use has-authority and put your expected authority it will work 100% . tasted
write it on your html tag has-authority="ROLE_ADMIN" or your expected user
On /config/SecurityConfiguration.java
You can change access of the api that you want like
.antMatchers("/api/authenticate").permitAll()
.antMatchers("/api/**").authenticated()
.antMatchers("/management/**").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/auth/*").hasAnyAuthority("ADMIN", "USER")
Or you can use auth.inMemoryAuthentication()
for more information read link below:
https://www.baeldung.com/spring-security-expressions
Related
I have a REST API to expose a resource, Employee with the following fields(id, firstName, LastName, Age, Salary). (Please note that this is a sample resource and my actual resource is more complex) This is an ASP.Net WEB API which serves to an Angular front end.
Few of my current REST API endpoints are as follows
HTTP GET (Get all the employees) api/employees
HTTP GET (Get a single employee by id) api/employees/{id}
PUT , POST and DELETE are following the normal REST standard
Now I have few different filtering requirements like Get all emloyees by FirstName, Get all Employees by Last Name, Get all employees who's salary is greater than 1000
in an RPC setup I would create methods like
GetEmployeesByFirstName('donald')
GetEmployeesByLastName('trump')
GetEmployeesBySalaryGreaterThan(1000)
and achieve this.
But I am a bit confused on how to design these URLs according to the REST API standards.
I thought of doing like below but I feel these are also not conforming to the REST standard (as I understand it)
api/employees/get-by-firstname?firstName=donald OR api/employees/by-firstname?firstName=donald
api/employees/get-by-lastname?lastName=trump OR api/employees/by-lastname?lastName=trump
api/employees/get-salary-greterthan?salary=1000 OR api/employees/salary-greterthan?salary=1000
I really think the URLs should be like
api/employees?firstName=donald
api/employees?lastName=trump
api/employees?salary=1000(hmm not sure about this one)
But I am having issues creating my ASP.Net Web API controller as the route is almost the same api/employees and it gives me exceptions
The project I am working on has some rules saying that we have to follow the REST standard when creating APIs. Can someone help me on how I should design my URLs in this kind of filtering situations
If you are querying employees then the following URLs should all hit the same action method
api/employees?firstName=donald
api/employees?lastName=trump
api/employees?salary=1000
To do this you should create an object that will capture the possible parameters:
public class EmployeeFilterParams{
public string firstName { get; set; }
public string lastName { get; set; }
public string salary { get; set; }
}
and then create the action in the Employees controller:
[HttpGet]
public ActionResult Get(EmployeeFilterParams params){
if (!string.IsNullOrEmpty(params.firstName)){
// do something here for firstName
}
... repeat for each parameter
}
Because this is a GET request ASP.Net's default model binding should populate the properties in params (EmployeeFilterParams).
This method has the added benefit that you can easily filter on multiple parameters i.e.
api/employees?firstName=donald&lastName=trump&salary=1000
THIS CODE IS UNTESTED BUT SHOULD GIVE YOU A GOOD STARTING POINT
I am a bit confused on how to design these URLs according to the REST API standards.
REST doesn't care what spelling conventions you use for your URLs. As far as a consumer is concerned, they are opaque identifiers. Any information encoded into the identifier is done at the server's discretion and for its own convenience.
Which is good in that it means that you, the server, can choose identifier spellings that work with whatever local routing library you happen to be using. So you can choose any spelling that makes ASP.Net Web API Controller easy to work with, and that's fine.
/api/employees/get-salary-greterthan?salary=1000
/api/employees/salary-greterthan?salary=1000
/api/employees?salary=100
/api/reports/employees-by-salary?greaterThan=1000
/api/reports/employees-by-salary/greaterThan/1000
/api/9048aa3e-9058-4248-8949-459bb4a02019
Those are all fine.
Identifiers that use key/value pairs in the query are convenient when you are using HTML to interact with your API, because the HTML forms can be used as a sort of URI template. If you are targeting clients with more sophisticated template capabilities, then you have more freedom about how you encode the information into the URI.
I have seen in most of the documents which explains REST url naming convensions saying that we should not use VERBs in the url (like "get" in the get-salary-greterthan part of the url).
https://www.merriam-webster.com/dictionary/put
https://www.merriam-webster.com/dictionary/post
https://www.merriam-webster.com/dictionary/patch
Notice that these URI work exactly as you would expect, even though put, post, and patch are all registered HTTP method tokens.
URI spelling conventions are analogous to spelling conventions for variable names - they are there just to make things "easy" for human beings. The machines don't care.
I would like to secure my rest endpoints in the backend. For example an author can query his books like this:
/books?authorId=5&login=username
#GetMapping("/books")
#Timed
public ResponseEntity<List<Book>> getAllBooks(
#RequestParam(value="authorId", required = false) String authorId,
#RequestParam(value="login", required = false) String login) {
if(!login.equals(SecurityUtils.getCurrentUserLogin().get())){
return ResponseEntity.status(401).build();
}
List<Book> result;
if(authorId!= null)
result = bookService.findByAuthorId(authorId);
else if("admin".equals(SecurityUtils.getCurrentUserLogin().get()))
result = bookService.findAll();
else return ResponseEntity.status(401).build();
return ResponseEntity.ok().body(result);
}
Preferable I would like to only pass the authorId in the params
/books?authorId=5
but since SecurityUtils only gives me the loginName I can't compare them and identify the user in the backend.
Also since it's a microservice I can't access the AccountService.java which is handled by the gateway.
It all works fine but it seems wrong? Is there a better way to allow certain querys only for certain users? Should I make another rest endpoint which handles specifally requests to get books for specific users?
Thank you
You are addressing 2 use cases: one for authors (list my books) and one for management (list all books) for security reasons but usually you may also want to return different data based on use case. It could be a good idea to have 2 different resources: /api/my_books for authors and /api/books for management, you could even use nested resources.
For returning different data (also for security reasons) you can use the DTO option of JHipster with a service layer to map them from entities rather than exposing entities in your REST controllers.
Also don't pass the user id as a request param, you should modify TokenProvider to add it to the token as a claim. If you don't want to add user id to the token, you should modify book entity in your service so that it references user login rather than internal id, as long as it is immutable it does not make a difference.
I use the security.yml with access_control to secure the API paths based on the user role. This works fine, but how do I secure specific parameters like /api/project/:id?
Different users have access to different project ids. Therefore a database call has to be made to check if this user has access to this project.
I tried to use $this->denyAccessUnlessGranted('GET', $projectId, 'Unauthorized access!'); in the ProjectController, which calls a custom Voter to check the database and therefore the access.
public function getProjectAction(Request $request, $id)
{
$this->denyAccessUnlessGranted('GET', $id, 'Unauthorized access!');
This works, but it seems very unpractical to add this code to 10+ actions in the ProjectController alone and also in many parts of the API.
Therefore my question: What is the best pratice to secure a REST api with symfony2, fosUserBundle and fosRestBundle
I would suggest introducing security voters.
http://symfony.com/doc/current/cookbook/security/voters_data_permission.html
Also create some kind of exception handler / listener, to catch your exceptions and make a specific error response.
http://symfony.com/doc/current/cookbook/service_container/event_listener.html
I know I ran across a post at some point, but I can't seem to find anything. It seems that by default, ServiceStack allows access to /auth via GET or POST. GET is not something we want in production.
I need to turn off GET access to /auth. Any ideas?
You can use the AuthenticateServices custom ValidateFn to add your own custom validation, e.g:
AuthenticateService.ValidateFn = (authService, verb, requestDto) => {
if (verb == HttpMethods.Get)
throw new NotSupportedException("GET's not allowed");
};
Otherwise you can add your own Restricting Services Attributes on services you don't own by using the fluent API for dynamically adding attributes, e.g:
typeof(Authenticate)
.AddAttributes(new RestrictAttribute(RequestAttributes.HttpPost));
Using Orchard 1.6 Iv created a new role 'FactoryWorker'. When this user logs in from the front end I want them to be navigated to one page only.
OrchardLocal/System/ManufacturedProducts
I have set this page to be a print screen of the order details so the factory worker will know what products to get ready for ship out & they wont be able to navigate as no menu appears, but also need the other pages blocked incase the user decides to enter the URL of a page they arnt allowed access to.
This is the only page I want this particular user to be able to access(after they login), and I have added a logout button, which logs out the user and returns them to the home page.
So iv been looking through editing a role, with permissions and content etc...but this all seems to be applying to forms and content in general. where the user can access any content type etc...
So can someone advise me on how to do this?
thanks for any replies
UPDATE
I forgot to mention that this is not a content type, item or part I am talking about.
I have created my own controller & View & VM which is accessible from the dash board (using the AdminMenu, which brings the admin user to OrchardLocal/System/ManufacturedProducts)
I have looked at Orchard.ContentPermissions Feature but it only seems to allow me to 1)Grant permissions for others or 2)Grant permission for own content
any ideas?
You can use a Request Filter, (I do not know if it is the best way) :
FilterProvider – defines the filter applied to each request. Resembles the way default ASP.NET MVC action filters work with the difference that it’s not an attribute. All FilterProvider objects are injected into the request pipeline and are applied to all requests (so you need to check if the current request is suitable for your filter at the beginning of an appropriate method).
From : http://www.szmyd.com.pl/blog/most-useful-orchard-extension-points
So you could implement something like this
public class Filter : FilterProvider, IAuthorizationFilter {
private readonly IAuthenticationService _authenticationService;
public Filter(IAuthenticationService authenticationService) {
_authenticationService = authenticationService;
}
public void OnAuthorization(AuthorizationContext filterContext) {
//If route is the restricted one
if (filterContext.HttpContext.Request.Url.AbsoluteUri.Contains("OrchardLocal/System/ManufacturedProducts")) {
//Get the logged user
IUser loggedUser = _authenticationService.GetAuthenticatedUser();
if (loggedUser == null)
return filterContext.Result = new HttpUnauthorizedResult();
//Get the Roles
var roles = loggedUser.As<IUserRoles>().Roles;
if (!roles.Contains("FactoryUser")) {
//User is not authorized
return filterContext.Result = new HttpUnauthorizedResult();
}
}
}
}
Note: Untested code!
EDIT: Also you could invert the logic and check if the logged user has the role 'FactoryUser' and restrict its access to every page except the one they should see.
Your module can create a new permission (look at one of the permissions.cs files for examples), then create a role that has only that permission. Have your controller action check that permission (again, many examples found by finding usage of the permissions defined in one of the permissions.cs).
You can use the Content Permissions module. Using this module you can attach a content item permission part to a content type. This part allows you to choose which roles can see the content when you create it.