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.
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.
So I'm currently learning/building a REST API backend server for my web application using NodeJS, ExpressJS, and MySQL as the database. My question is in regards to the best way to implement authorisation to ensure User A does not access or edit the data belonging to another User. Please note that I understand there are a lot of examples for implementation of role based authorisation (ie user groups vs admin groups, etc) but this is not what I'm asking. Instead, how do I authorise a user against the data they are accessing?
It is possible that I'm overthinking this and this is not even necessary; that I should just check whether the data belongs to the user in every SQL query, but I thought I'd ask if there's a middleware or policy architecture that takes care of this, or maybe even authorise through caching.
The only solution I can think of is that every SQL query returns the the user id with the result, then I just create a service that checks every result if the id matches or not. If yes, then proceed. If not rollback the query and return unauthorised error. Is this ok?
I very much appreciate your advice, help, and if you can point me in the right direction.
Many thanks in advance.
Save the userId (or ownerId) in every table, and create a middleware where each db access method requires the userId as a parameter, for example:
readOne(id, userId) {
// implements SELECT * FROM example WHERE id = id AND userId = userId
}
updateOne(id, data, userId) {
// implements UPDATE example SET data = data WHERE id = id AND userId = userId
}
...
For security reasons, never send as a response "Requested data exist by you aren't the owner".
The simplest things usually work best. You wouldn't have to have a special service for checking authorization rights for every entity and you can do it at data access level eg. SELECT * FROM foo WHERE user_id = :currentUser or UPDATE foo SET foo = bar WHERE user_id = :currentUser
It also depends whether you want to notify the user about unallowed access via HTTP401 or not to reveal that such a resource even exists for different user HTTP404.
For HTTP401 the scenario would be:
const entity = loadFromDB(id);
if(entity.userId !== currentUserId) {
res.send(401);
return;
}
... update entity logic ...
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
I'm having trouble finding documentation on the request object argument used in replication filters ('req' in the sample below):
function(doc, req) {
// what is inside req???
return false;
}
This old CouchBase blog post has a little code snippet that shows the userCtx variable being a part of the request object:
What is this userCtx? When you make an authenticated request against
CouchDB, either using HTTP basic auth, secure cookie auth or OAuth,
CouchDB will verify the user’s credentials. If they match a CouchDB
user, it populates the req.userCtx object with information about the
user.
This userCtx object is extremely useful for restricting replication of documents to the owner of the document. Check out this example:
function(doc, req) {
// require a valid request user that owns the current doc
if (!req.userCtx.name) {
throw("Unauthorized!");
}
if(req.userCtx.name == doc.owner) {
return true;
}
return false;
}
But the problem now is that CouchDB requires the filter method to be explicitly chosen by the initiator of the replication (in this case, the initiator is a mobile user of my web app):
curl -X POST http://127.0.0.1:5984/_replicate \
-d '{"source":"database", \
"target":"http://example.com:5984/database", \
"filter":"example/filtername"
}'
The Question
Is there a way to enforce a specific filter by default so that users are restricted to replicating only their own data? I'm thinking the best way to do this is to use a front end to CouchDB, like Nginx, and restrict all replication requests to ones that include that filter. Thoughts? Would love a way to do this without another layer in front of CouchDB.
Data replication stands right with user ability to read data. Since if your users shares data within single database all of them has right to replicate all of them to their local couches. So you couldn't apply any documents read restriction unless you've split single shared database into several personal ones - this is common use case for such situations.
There is no any way to enforce apply changes feed filter or other parameters like views has. However, you can use rewrites to wraps requests to some resources with predefined query parameters or even with dynamic ones. This is a little not solution that you'd expected, but still better that nginx and some logic at his side: probably, you'd to allow users to specify custom filters with custom query parameters and enforce you're own only if nothing specified, right?
P.S. Inside req object is very useful about current request. Partially it was described at wiki, but it's a little out of date. However, it's easily to view it with simple show function:
function(doc, req){
return {json: req}
}
I have a question of how to better organize the implementation of the following functionality.
Suppose a user needs to be registered into the system by unique email and password (first step) and then he should confirm registration (second step). I have several choices of structuring implementation of first step (registration) between application services/domain services/user entity and I'm not sure which one is better.
First option:
AppService:
var existingUser = UserRepository.GetUserByEmail(email);
if (existingUser != null)
{
throw new ValidationException(...);
}
var newUser = UserFactory.CreateUser();
newUser.Register(email, password);
UserRepository.Save(newUser);
// commit
So here, we do not use any domain service. The thing which I personally don't feel confortable is that Email uniqueness business rule is checked in the Application Service, this being a business rule.
Second option:
AppService:
var user = UserRegistrationDomainService.RegisterUser(email, password);
UserRepository.Save(user);
// commit
UserRegistrationDomainService:
User RegisterUser(email, password)
{
var existingUser = UserRepository.GetUserByEmail(email);
if (existingUser != null)
{
throw new ValidationException(...);
}
var newUser = UserFactory.CreateUser();
newUser.Register(email, password);
return newUser;
}
What I don't like here, is that this solution is not quite symmetric with the implementation of second step, where we just get the user from repository and call User.ConfirmRegistration(). So for registration confirmation we do not need any domain service whereas for registration, in second option, we use such service.
Which option is better? Can the application service from first option contain email uniqueness validation?
Personally I think the Validation for that lives in the Domain (either the Entity of the service). The rule after all, is required due to a business rule.
It would be preferable in option 2 for the application services not to be responsible for saving the user, this is blurring the lines of responsibilities and it would be nicer if the domain service handled it. And the application service would simply call UserRegistrationDomainService.RegisterUser(email, password)
Option 1 means that the unique email rule is application-specific. In other words, if you take the Domain dll (or jar, module, etc.) to reuse it in another application, the rule won't be there any more.
Since we can reasonably consider that rule to be application-agnostic, I'd choose option 2.
Another solution could be to implement it in the Factory instead. After all, this is where you'll typically put the validation logic upon creation of your User (null/empty name checking, email format verification, and so on) so why not centralize all creation rules in the same place ?