How to accessgetmapping json response in spring boot program? - spring

This is my JpaRepository interface ---
#Repository
public interface usernameExists extends JpaRepository<user, Long>{
boolean existsByUsername(String userName);
}
This is my getmapping controller ---
#Autowired
private usernameExists usernameExists;
#GetMapping("/email")
public boolean doesUsernameExists(#RequestParam String username) throws IOException, InterruptedException{
System.out.println("Inside doesUsernameExists");
return this.usernameExists.existsByUsername(username);
}
When I hit the get request http://localhost:8083/email?username=sandeep#gmail.com I am getting response as true
enter image description here
But, I want to get that response in my spring boot application memory .How to achieve this ?

Related

[org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation]

I am new to Spring data jpa, trying to create a simple spring boot - data jpa- hibernate application. I am getting 2021-04-03 20:24:40.478 WARN 33252 --- [nio-8081-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation]
in my console when I hit the url http://localhost:8081/users Below is my controller code,
#RestController
public class UserController {
#Autowired
private UserService userService;
#GetMapping(value="/users")
public List<User> getAllUsers() {
List<User> result = userService.getAllUsers();
return result;
}
}
Service class -
#Service
public class UserService {
#Autowired
private UserRepository userRepository;
public List<User> getAllUsers() {
List<User> r = (List<User>) userRepository.findAll();
return r;
}
}
Repository interface-
#Repository
public interface UserRepository extends CrudRepository<User, Integer>{
}
I have gone through various solutions available online but nothing seems to work. Thanks in advance for the help.
There is some problem with "Accept" header with which your browser is sending the request. Can you include your http request browser trace?

Accessing current ClientDetails inside custom UserDetailsService

I'm using Spring Boot OAuth Authorization Server (old stack) and implementing my own versions of ClientDetailsService and UserDetailsService, using Oauth2 password flow.
Our JpaClientDetailsService implements loadClientByClientId and returns a ClientDetails, with the details of the client that is being authenticated.
#Service
public class JpaClientDetailsService implements ClientDetailsService {
#Override
public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {
BaseClientDetails baseClientDetails = new BaseClientDetails(...);
//do processing....
return baseClientDetails;
}
}
After that, the method loadUserByUsername of our implementation of JpaUserDetailsService is called, receiving the username of user that is trying to authenticate:
#Service
public class JpaUserDetailsService implements UserDetailsService {
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return null;
}
}
My question is:
How could I access the current ClientDetails, returned by JpaClientDetailsService.loadClientByClientId inside JpaUserDetailsService.loadUserByUsername?
Thanks!
I realized that SecurityContextHolder.getContext().getAuthentication() contains information about the client that is being authenticated. So, I was able to get the client's name and load it's data as follow:
#Service
public class JpaUserDetailsService implements UserDetailsService {
#Autowired
private OAuthClientsRepository oAuthClientsRepository;
#Override
public org.springframework.security.core.userdetails.UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//Gets the Authentication from SecurityContextHolder
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
//ClientId is 'Principal's' Username
var clientId = ((User) authentication.getPrincipal()).getUsername();
//Gets clientDetails from JPA Repository. This would execute another Roundtrip to Database, but since we have 2nd level cache configured, this
//problema is minimized.
ClientDetails authClient = oAuthClientsRepository
.findByClientId(clientId)
.orElseThrow(() -> new NoSuchClientException(String.format("ClientId '%s' not found", clientId)));
//....
}
}
That's it.

Mock Spring's remote JWT service

I'm currently using RemoteTokenServices class:
#Configuration
#EnableResourceServer
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Value("${auth-server.url}")
private String authEndpoint;
#Value("${security.oauth2.client.client-id}")
private String clientId;
#Value("${security.oauth2.client.client-secret}")
private String clientSecret;
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId("ms/legacy");
}
#Bean
public ResourceServerTokenServices tokenService() {
RemoteTokenServices tokenServices = new RemoteTokenServices();
tokenServices.setClientId(clientId);
tokenServices.setClientSecret(clientSecret);
tokenServices.setCheckTokenEndpointUrl(authEndpoint + "/uaa/oauth/check_token");
return tokenServices;
}
}
I want to be able to mock this easily and properly for all my endpoints integration tests, knowing that:
the JWT is decoded in a OncePerRequestFilter to get some crucial info
I'm not interested in testing auth failures (well I am but that's not something that we want to do on each endpoint)
Is there a standard way to:
Produce a JWT token by hand ?
Mock all token service accesses easily ?
The expected result would be that I can write an endpoint test with only a few extra lines to setup the right JWT in the request, and the token service would agree on its validity dumbly.
Given that we don't want to test security at all, the best solution for this kind of case is to:
use standard Spring tests security management #WithMockUser along with MockMvc
adapt the ResourceServerConfigurerAdapter for tests:
create a base class that hosts all the config except for tokens
create an inheriting class for non-tests profiles (#ActiveProfiles("!test")) that hosts the token specific configuration
create an inheriting class for test profile that deactivates the remote token check (security.stateless(false);)
make the test classes use test profile
inject the proper token-extracted infos at the right time in tests
Here is how it was implemented in practice:
Base ResourceServerConfigurerAdapter so that the configuration has a major common part between tests and non-tests contexts:
public class BaseResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId("ms/legacy");
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().permitAll().and().cors().disable().csrf().disable().httpBasic().disable()
.exceptionHandling()
.authenticationEntryPoint(
(request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED))
.accessDeniedHandler(
(request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED));
}
}
Its implementation outside for non-test:
#Configuration
#EnableResourceServer
#EnableGlobalMethodSecurity(prePostEnabled = true)
#Profile("!test")
public class ResourceServerConfiguration extends BaseResourceServerConfiguration {
#Value("${auth-server.url}")
private String authEndpoint;
#Value("${security.oauth2.client.client-id}")
private String clientId;
#Value("${security.oauth2.client.client-secret}")
private String clientSecret;
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId("ms/legacy");
}
#Bean
public ResourceServerTokenServices tokenService() {
RemoteTokenServices tokenServices = new RemoteTokenServices();
tokenServices.setClientId(clientId);
tokenServices.setClientSecret(clientSecret);
tokenServices.setCheckTokenEndpointUrl(authEndpoint + "/uaa/oauth/check_token");
return tokenServices;
}
}
And for tests:
#Configuration
#EnableResourceServer
#ActiveProfiles("test")
public class TestResourceServerConfigurerAdapter extends BaseResourceServerConfiguration {
#Override
public void configure(ResourceServerSecurityConfigurer security) throws Exception {
super.configure(security);
// Using OAuth with distant authorization service, stateless implies that the request tokens
// are verified each time against this service. In test, we don't want that because we need
// properly isolated tests. Setting this implies that the security is checked only locally
// and allows us to mock it with #WithMockUser, #AutoConfigureMockMvc and autowired MockMVC
security.stateless(false);
}
}
Inject token specific info with a request filter for tests:
#Component
#ActiveProfiles("test")
public class TestRequestFilter extends OncePerRequestFilter {
private Optional<InfoConf> nextInfoConf = Optional.empty();
// Request info is our request-scoped bean that holds JWT info
#Autowired
private RequestInfo info;
#Override
protected void doFilterInternal(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
if (nextInfoConf.isPresent()) {
info.setInfoConf(nextInfoConf.get());
}
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
public void setNextInfoConf(InfoConf nextInfoConf) {
this.nextInfoConf = Optional.of(nextInfoConf);
}
public void clearNextInfoConf() {
nextInfoConf = Optional.empty();
}
}
And of course make the JWT parsing do nothing when there's no JWT.
We also wrote a small utility component to create the relevant info to inject.
A typical integration test will be like this:
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#AutoConfigureMockMvc
#ActiveProfiles("test")
public class TestClass {
#Autowired
protected MockMvc mockMvc;
#Before
public void before() {
// Create an user in DB
// Inject the related information in our filter
}
#After
public void after() {
// Cleanup both in DB and filter
}
#Test
#WithMockUser
public void testThing() throws Exception {
// Use MockMVC
}
}
Another solution is to indeed mock the ResourceServerTokenServices but in fact it's much more a pain to build proper tokens, and using Spring's standard security mock seems much more appropriate.

How to secure REST APIs and not JpaRepository

I am trying to have unsecured DAOs and secured REST APIs using Spring Data, Spring Data JPA and Spring Data Rest.
For example, I have the DAO repository which should not be secured since I want to call its methods from anywhere without having to provide an authentication:
#RepositoryRestResource(exported = false, path = "persons")
public interface UserRepository extends JpaRepository<User, Long> {
int countByUsername(String username);
void deleteByUsername(String username);
Optional<User> findByUsername(String username);
}
And I have the REST repository, which must be secured using authorizations of the current user:
#RepositoryRestResource(path = "persons")
#PreAuthorize("hasAuthority('FETCH_USER')")
public interface UserRestRepository extends PagingAndSortingRepository<User, Long> {
#PreAuthorize("hasAuthority('DELETE_USER')")
#Override
void delete(User user);
#PreAuthorize("hasAuthority('DELETE_USER')")
#Override
void deleteAll();
#PreAuthorize("hasAuthority('DELETE_USER')")
#Override
void deleteAll(Iterable<? extends User> iterable);
#PreAuthorize("hasAuthority('DELETE_USER')")
#Override
void deleteById(Long id);
#Override
Iterable<User> findAll();
#Override
Page<User> findAll(Pageable pageable);
#Override
Iterable<User> findAll(Sort sort);
#Override
Iterable<User> findAllById(Iterable<Long> iterable);
#Override
Optional<User> findById(Long id);
#PreAuthorize("hasAuthority('SAVE_USER')")
#Override
<S extends User> S save(S s);
#PreAuthorize("hasAuthority('SAVE_USER')")
#Override
<S extends User> Iterable<S> saveAll(Iterable<S> iterable);
}
The problem here is that it seems to automatically use the JpaRepository to create and configure the REST service, so I am forced to add exported = false on it to only expose methods of the REST repository, BUT there's still a problem, if I want to set change path (to persons) on the REST service, it doesn't work, I still need to duplicate it on the JpaRepository...
Am I not supposed to do like this ?
Is it not possible to create a separate JpaRepository and PagingAndSortingRepository, one for the DAO and the other for the REST ?
Secure the endpoints (URLs) using Spring Security rather than the
methods. javabullets.com/spring-security-spring-data-rest
See Alan Hays comment

How can I access Spring ConfigurationProperties inside a custom JsonDeserializer?

I have a custom Json Deserializer that I am trying to Autowire ConfigurationProperties into. However, the property is always null. I tried using the SpringBeanAutowiringSupport but for some reason the CurrentWebApplicationContext is null.
How can I get the #Autowired to work in my custom deserializer?
Update:
I am using #JsonDeserialize(using = Deserializer.class) on my domain class, which is be utilized through a RestTemplate call in a service class.
I am using Spring Boot 1.4.
HealthDeserializer
public class HealthDeserializer extends JsonDeserializer<Health> {
#Autowired
private HealthMappings mappings;
#Override
public Health deserialize(JsonParser jp, DeserializationContext ctx) throws IOException, JsonProcessingException {
mappings.lookup(...);
}
}
HealthMappings
#Component
#ConfigurationProperties(prefix="health_mapping")
public class HealthMappings {
...
}

Resources