which crud operation in rest to use post or delete? - spring

i have created a bank application where i want to write a rest service to delete account . so for that we need an account no . for that i think for security reasons i cant pass account no in url . so i am passing it in request body . i think if i try using it with delete it runs fine but again that could be a security issue .
so in that case will i need to use post instead of delete so that i can pass account no in request body ?
#PostMapping("/account")
public void deleteAccount(#RequestBody #Valid final AccountNoDto accountNoDto) {
return accountService.deleteAccount(accountNoDto);
}
or
#DeleteMapping("/account/{accountNo}")
public void deleteAccount(#PathVariable Long accountNo) {
return accountService.deleteAccount(accountNo);
}

You should use #DeleteMapping because you are deleting a record.
The HTTP verbs should be compliant with what the function does.
But dont send the account Number along with the endPoint.
Write the endpoint as -
#DeleteMapping("/account")
The Account Number should be retrived at the backend from the token you will be sending along with the request.So All requests GET,POST,PUT,DELETE will have the same uri and the account number will be fetched from the token at the backend.
If you want to know how it is done in spring read about SecurityContextHolder class

Idealy we use #DeleteMapping for delete operation and we use #PostMapping for new creation and updation of data . I dont think account id is that much sensitive information to reveal in url. You can go for #DeleteMapping

Related

how to delete data from a table?

I'm a laravel programmer and I have to develop a project for college in spring.
I am not able to delete data from the table.
In laravel, to delete data from the table, you have to create a form and inside this form you can pass the delete method.
I've done a lot of research but the examples don't show the html.
Controller:
// Delete
#DeleteMapping("/autor/deletar/{id}")
public void delete(#PathVariable("id") long id)
{
authorservice.delete(id);
}
AuthorServiceImplement
#Override
public void delete(Long id) {
repositorio.delete(repositorio.findById(id).get());
}
Html
<a th:href="#{/autor/deletar/{id}(id=${author.id})}">
Deletar
</a>
When I try to delete, I get an error "get method not supported". Do I have to change anything in html anyway or is there something wrong with my code?
If you are testing it via a web browser, it's always using the HTTP Method GET. You need to use Postman or Insomnia for exemple to send HTTP requests.
As you are using #DeleteMapping("/autor/deletar/{id}") it says that this function is called when doing an HTTP request to /autor/deletar/{id} with the method DELETE
EDIT
If you just want to test it via your web browser, you can always replace #DeleteMapping("/autor/deletar/{id}") by #GetMapping("/autor/deletar/{id}")

How to catch what is POST'ed to rest api

I have a rest api set up at api/books, and one can send a new book object there, and it will be added to the database. The guestion is, how can I correctly catch what is being POST'ed, so one can for example, validate what is being sent?
#RequestMapping(value="/api/books", method = RequestMethod.POST)
public String bookSavePost(#RequestBody Book book) {
bookRepository.save(book);
return "redirect:/api/books";
}
This works, as in it saves the book and I can catch what the user sends, but with this enabled, it overrides the default REST method, which doesn't allow one to actually view the api anymore. If I change this particular method to GET, it returns a string "redirect:/api/books", so it doesn't even redirect anything. Is there some way to actually redirect it to the rest api endpoint?
You can write your own reuquest Interceptor .
Spring provides HandlerInterceptor class :
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/HandlerInterceptor.html
Here is a quick sample how to do this:
https://www.baeldung.com/spring-mvc-handlerinterceptor
A redirect requires three two things to be successful: A HTTP code of 301 or 302 AND a location header that includes the endpoint to which you want the client to visit.
E.g., in the headers section you should have
location: '/correct/endpoint'

how expired OAuth2 Tokens are detected?

I'm a beginner in Spring Boot and I set up OAuth2 and all work well with inMemory () data.
I'm trying to store the Token in DB but I want the client to stay in memory because I will always use a single client for this application
so i created the necessary tables using schema.sql i see that only the oauth_access_token and oauth_refresh_token tables that will be used and when i make a request to request a token the system returns the old one if it is still valid and a new one if not(this is good but..). For this reason I have difficulty understanding how the system can know that a token is expired or not? (knowing that I do not define JWT token or any other specific type of token explicitly)
The token in this scenario is an instance of class DefaultOAuth2AccessToken which has field
expiration
which takes care of expiry of a token. Object of this class is serialized so that it can be stored in database.Upon deserialization values are populated in respective fields and below method is invoked to check for expiry.
public boolean isExpired() {
return this.expiration != null && this.expiration.before(new Date());
}
The class DefaultTokenServices has createAccessToken() method to create token.
just go and have a look at these classes to see the working.
Thanks for your answer
After some research in the documentation i can now understand how the token is validated.
the token (DefaultOAuth2AccessToken) is stored as a serialized object in the DB and it will be retrieved from the database to validate expiration date , and many other operation ...

Spring OAuth2.0 passing query parameters to login page

Problem: I make a request that requires authentication. OAuth server will save the original request and redirect to "/login". I need to pass a query parameter from the original request to the login form (I need this before the form is submitted in order to filter to the correct AuthenticationProvider).
Trying to filter on super(new AntPathRequestMatcher("/login", "GET")); is too late. The ServletRequest is already a redirect to login. Therefore, I tried to create a custom auth entry point which extended LoginUrlAuthenticationEntryPoint. I simply did an Override on determineUrlToUseForThisRequest to append my query from the original request. This idea worked for the URL's sake, but unfortunately Spring's /login page does not show up unless the URL is exactly "/login".
Any idea on how to work around this would be greatly appreciated!
EDIT/Update
This is not yet tested but — if I use a custom AuthenticationEntryPoint I can redirect to a custom login page endpoint. This endpoint would take in a #RequestParamand be put into a hidden field on the login form. Then I can POST with that new field added to WebAuthenticationDetailsSource. From here, my POST filter should correctly choose a provider.
I configured my setup as stated above in my Edit/Update. It works.
1) I configured a CustomAuthenticationEntryPoint
2) Did a #Override protected String determineUrlToUseForThisRequest()
to build my login string with a query parameter passed in from client's request.
3) LoginController does this
#GetMapping("/login")
public ModelAndView showCustomLoginForm(#Valid #RequestParam(value = "realm_name", required=false) final String realmName) {
CustomLoginForm form = new CustomLoginForm(realmName);
return new ModelAndView(CUSTOM_LOGIN_FORM_VIEW, CUSTOM_LOGIN_FORM_MODEL, form);
}
where realm_name is my hidden field in the form that I need upon POST.

Dynamically changing JWT subject field

I successfully implemented JWT as a authentication filter in my web application. When user's login is successful, I am creating a new JWT and assigning userName in the sub field of JWT.
In the subsequent request's I am using userName in the JWT sub field to identify the user. But what if the user changes his userName in the update section of the application. Is there way, I can update the value of sub field in JWT ?
What I am thinking!
I am thinking of getting the existing JWT in the RestController and after updating the userName, I will update the JWT with new userName and again send back to the client. Is this fine or is there a better approach?
I think I should refresh the token after update is done and send back the refreshed token back to client.
#RequestMapping( value = "/account", method = RequestMethod.POST )
public ResponseEntity<?> updateAccount( #RequestBody UserDetailsBean userDetailsBean, HttpServletRequest request,
HttpServletResponse response )
{
try
{
UserAccessDetails accessDetails = getLoggedInUser();
UserDetailsBean updatedUserBean = userService.updateAccount(userDetailsBean, accessDetails);
// send updated jwt incase of mobile number update by user
response.addHeader(SecurityConstants.HEADER_STRING,
SecurityConstants.TOKEN_PREFIX + refreshJWT(updatedUserBean.getMobileNumber()));
return buildResponse(updatedUserBean);
}
catch( DataException e )
{
return buildError(e);
}
}
private String refreshJWT( String subject )
{
return Jwts.builder().setSubject((subject))
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
.signWith(SignatureAlgorithm.HS512, SecurityConstants.SECRET).compact();
}
This is working. If anyone has a cleaner and industry standard approach please specify.
If you allow your users to change their usernames, they should also have an immutable user id that can be used to identify any data or activity associated with a given user. Otherwise, any time a user changes his or her name, you will either lose the ability to audit the user's past actions or you will have to update all references to that username in the database. What's worse is if there are references to an old username in the database and another user takes that username -- now you have data from one user now being associated with another due to incorrect handling of user identification.
Now with that said, the sub claim should contain this immutable user id. You can create a separate claim for the mutable username. When a username is changed, you now only need to change a single field in the database (assuming that only the users table references this mutable username). You could then use the refresh token retrieve a new token that would contain the latest username that could then be used by your API as needed.
Using this approach, you should be careful to only use the username claim for display purposes, not for identifying the logged in user due to the fact that it is mutable. The sub claim containing the user id would serve the purpose of identifying a user.
It is also important to note that this solution requires no special logic for "updating the sub claim." You would be using the same logic that you're already using to generate a token for a supplied refresh token.

Resources