Spring TestRestTemplate authentication - authentication

I am trying to build Spring Boot test to test rest API, so that I can get Principal from the request and use that to identify the user.
Server returns
{"timestamp":1502014507361,"status":403,"error":"Forbidden","message":"Access
Denied","path":"/hello"}
What am I missing here?
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class RestTemplateTest {
#Autowired
TestRestTemplate testRestTemplate;
#Test
public void testit() {
testRestTemplate.withBasicAuth("user", "password");
String responsePayload = testRestTemplate.getForObject("/hello", String.class);
}
#RestController
public class GreetingController {
#RequestMapping("/hello")
public String heipat(Principal principal) {
String string = "hello there";
return string;
}
#Configuration
#EnableWebSecurity
static class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
public void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.authorizeRequests().anyRequest().hasRole("USER");
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
}

You need to be authenticated first. like requesting a /login API.
Also you need to make the login API accessible by everyone by doing this:
http.csrf().disable().authorizeRequests()
.antMatchers("/login").permitAll()
When you includes WebSecurityConfig you will have basic usernamerAndPassowrd authentication.

Related

Quarkus inject RequestInfo in bean

I'm able to inject RequesInfo instances in Jaxrs resources by using the #Context annotation.
What I'm trying to do is to inject the same interface but in a bean that is not a Jaxrs resource. This fails with a NPE when accessing the variable.
#RequestScoped
public class Service {
#Context
private ResourceInfo resourceInfo;
public Service() {
}
public ResourceInfo getResourceInfo() {
return resourceInfo;
}
}
#ApplicationScoped
#Path("/hello")
public class GreetingResource {
private final Service service;
#Inject
public GreetingResource(Service service) {
this.service = service;
}
#GET
#Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "Hello RESTEasy";
}
#GET
#Path("service")
#Produces(MediaType.TEXT_PLAIN)
public String resourceInfoService() {
return service.getResourceInfo().getResourceClass().getName();
}
}
I have looked at Jaxrs spec but I did saw any clear evidence saying that this should be supported or not. I've used this technique in other spec implementations like Payara, but in Quarkus it fails.

Getting noBaseStepListener error while using Serenity RestAssured

I am trying to implement Rest Assured framework with cucumber
I am facing a weird scenario that I have defined all my step definitions of my feature file then also I am getting error as below when I run my feature file:-
Step undefined
You can implement this step and 3 other step(s) using the snippet(s) below:
#Given("I create new service by using create service API data")
public void i_create_new_service_by_using_create_service_api_data() {
// Write code here that turns the phrase above into concrete actions
throw new io.cucumber.java.PendingException();
}
and When I run the same from Junit Testrunner then I get error as below :-
INFO net.serenitybdd.rest.decorators.request.RequestSpecificationDecorated - No BaseStepListener, POST /services not registered.
In my framework I am defining basepackage containing base class file which is as below :-
public class TestBase {
public static Properties propertyConfig = new Properties();
public static FileInputStream fis;
public static Response response;
public static RequestSpecification requestSpecification;
public static void loadPreConfigs(){
try {
fis = new FileInputStream("./src/test/resources/ConfigurationURLs/config.properties");
try {
propertyConfig.load(fis);
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
RestAssured.baseURI=propertyConfig.getProperty("BaseURI");
}
}
Then I have a ApiCall package which contains all class files which have request specification and respective response storing rest API calls
The APICall file is given below:-
public class PostRequestCall extends TestBase {
private static String productVal;
public static int getProductVal() {
return Integer.parseInt(productVal);
}
public static void setProductVal(String productVal) {
PostRequestCall.productVal= productVal;
}
public RequestSpecification definePostRequest(){
requestSpecification= SerenityRest.given();
requestSpecification.contentType(ContentType.JSON);
return requestSpecification;
}
public Response CreateService(String serviceName){
JSONObject jsonObject=new JSONObject();
jsonObject.put("name",serviceName);
response=definePostRequest().body(jsonObject).post(propertyConfig.getProperty("createService"));
return response;
}
}
Then I have step file which are the class file in which I define the steps of serenity given below:
public class PostRequestSteps {
PostRequestCall postRequestCall=new PostRequestCall();
#Step
public RequestSpecification setPostSpecification(){
TestBase.requestSpecification=postRequestCall.definePostRequest();
return TestBase.requestSpecification;
}
#Step
public Response setPostRequestCall(String serviceName){
TestBase.response=postRequestCall.CreateService(serviceName);
return TestBase.response;
}
}
And I have defined a package which contains all the step definition classes one such class is as below :-
public class PostRequest_StepDefinitions {
String serviceID;
#Steps
PostRequestSteps postRequestSteps=new PostRequestSteps();
#Before
public void setUp() {
TestBase.loadPreConfigs();
}
#Given("I create new service by using create service API data")
public void i_create_new_service_by_using_create_service_api_data() {
postRequestSteps.setPostSpecification();
}
#When("I provide valid name {string} for service creation")
public void i_provide_valid_name_for_service_creation(String serviceName) {
TestBase.response=postRequestSteps.setPostRequestCall(serviceName);
}
#And("I save the id of created service")
public void i_save_the_id_of_created_service() {
serviceID=TestBase.response.jsonPath().get("id").toString();
PostRequestCall.setProductVal(serviceID);
}
#Then("I validate status code {int}")
public void i_validate_status_code(int statusCode) {
Assert.assertEquals(TestBase.response.getStatusCode(),statusCode);
}
The Junit Runner file and feature files are below

Spring webflux restdocs - By passing security for test cases

I am using Spring webflux security for my application and trying to write Spring webflux restdocs. Getting unauthorized error for test cases. Is there anyway to by pass security for rest doc test cases? Is it possible to control thru property?
#ExtendWith({ SpringExtension.class, RestDocumentationExtension.class })
#WebFluxTest({ RegistrationRequesttHandler.class })
#AutoConfigureWebTestClient(timeout = "100000")
class RegistrationRequestHandlerTest {
#Autowired
ApplicationContext context;
#MockBean
private OrgRepository orgRepository;
#MockBean
private UserRepository usrRepository;
#Captor
private ArgumentCaptor<Organization> orgInputCaptor;
#Captor
private ArgumentCaptor<Mono<Organization>> orgMonoInputCaptor;
#Captor
private ArgumentCaptor<User> usrInputCaptor;
private WebTestClient webTestClient;
#BeforeEach
void setUp(RestDocumentationContextProvider restDocumentation) {
webTestClient = WebTestClient.bindToApplicationContext(context).configureClient()
.filter(documentationConfiguration(restDocumentation)).responseTimeout(Duration.ofMillis(100000))
.build();
}
#Test
public void testRegister() {
final Register register = new Register();
final Organization org = new Organization();
final User usr = new User();
given(orgRepository.save(orgInputCaptor.capture())).willReturn(Mono.just(org));
given(usrRepository.save(usrInputCaptor.capture())).willReturn(Mono.just(usr));
webTestClient.mutateWith(csrf()).post().uri(REGISTER_PATH).contentType(APPLICATION_JSON).bodyValue(register).exchange()
.expectStatus().is2xxSuccessful().expectBody();
StepVerifier.create(orgMonoInputCaptor.getValue()).expectNext(org).expectComplete();
then(usrRepository).should().save(usrInputCaptor.capture());
}
private String buildRegister() {
// TODO Auto-generated method stub
return null;
}
}
Here, I am testing /register api which is been set to permitAll().
#Bean
public SecurityWebFilterChain securitygWebFilterChain(ServerHttpSecurity http) {
return http.authorizeExchange().matchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
.pathMatchers("/register", "/login").permitAll()
.anyExchange().authenticated()
.and().formLogin()
.securityContextRepository(securityContextRepository())
.and()
.exceptionHandling()
.accessDeniedHandler(new HttpStatusServerAccessDeniedHandler(HttpStatus.BAD_REQUEST))
.and().csrf().disable()
.build();
}
But still getting 401 error for testRegister. Do we need to create test bean for SecurityWebFilterChain also with permitAll for register API?
By default, spring-security enabled for Test classes, in order to test public APIs we have to skip security by excluding AutoConfiguration.
#ExtendWith(SpringExtension.class)
#WebFluxTest(controllers = AuthController.class, excludeAutoConfiguration = ReactiveSecurityAutoConfiguration.class)
public class AuthControllerTest {
#Autowired
private WebTestClient webClient;
#MockBean
AuthService authService;
#Test
public void shouldSignUp() {
UserDto userDto = UserDto.builder()
.firstName("firstName")
.lastName("lastName")
.phone("phone")
.password("password")
.email(TEST_EMAIL)
.role(UserRoles.ADMIN)
.build();
when(authService.signup(any(UserDto.class))).thenReturn(Mono.just(userDto));
webClient
.post().uri("/auth/v1/signup")
.bodyValue(userDto)
.exchange()
.expectStatus()
.isOk()
.expectBody(UserDto.class);
}
}
https://github.com/Brajendra/springboot-reactive-starter-kit

Rest Service URL giving Not working and giving Error

So I have been trying to make this rest service work and I have been on it for a few days but just can't get the URL to work no matter what I try. I first tried every suggestion the internet gave regarding to the web.xml file. Once I realised it's a last cause I tried the JAXRSConfiguration class with an '#ApplicationPath("/")' annotation.
So here is the JAXRS Class:
#ApplicationPath("api")
public class JAXRSConfiguration extends Application {
public JAXRSConfiguration() {
BeanConfig beanConfig = new BeanConfig();
beanConfig.setVersion("2.0.0");
beanConfig.setSchemes(new String[]{"http"});
beanConfig.setHost("localhost:8080");
beanConfig.setBasePath("/MyApp/api");
beanConfig.setResourcePackage("rest");
beanConfig.setPrettyPrint(true);
beanConfig.setScan();
getClasses();
}
#Override
public Set<Class<?>> getClasses() {
final Set<Class<?>> classes = new HashSet<>();
classes.add(UserResource.class);
classes.add(MessageService.class);
return classes;
}
}
And here is one of my resource files:
#Path("/users")
public class UserResource {
private UserService service = new UserService();
#DELETE
#Path("/{userId}")
public void deleteMessage(#PathParam("userId") int id) {
service.deleteUser(id);
}
#POST
#Path("/{userId}/follow/{userToFollowId}")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public void followUser(#PathParam("userToFollowId") int userId, int userToFollowId) {
service.followUser(userId, userToFollowId);
}
#POST
#Path("/register")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public User registerUser(User user) {
return service.registerUser(user);
}
#PUT
#Path("/{userId}")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.TEXT_PLAIN)
public User updateUser(User user) {
return service.updateUser(user);
}
#GET
#Path("/{userId}")
#Consumes(MediaType.TEXT_PLAIN)
#Produces(MediaType.APPLICATION_XML)
public User getUser(#PathParam("userId") int id) {
return service.getUser(id);
}
#GET
#Produces(MediaType.APPLICATION_XML)
public List<User> getAllUsers() {
return service.getAllUsers();
}
#GET
#Path("/{userId}/followers")
#Consumes(MediaType.TEXT_PLAIN)
#Produces(MediaType.APPLICATION_XML)
public List<User> getFollowers(#PathParam("userId") int id) {
return service.getFollowers(id);
}
#GET
#Path("/{userId}/followings")
#Consumes(MediaType.TEXT_PLAIN)
#Produces(MediaType.APPLICATION_XML)
public List<User> getFollowings(#PathParam("userId") int id) {
return service.getFollowings(id);
}
#GET
#Path("/{userId}/kweets")
#Consumes(MediaType.TEXT_PLAIN)
#Produces(MediaType.APPLICATION_XML)
public List<Kweet> getKweets(#PathParam("userId") String username) {
return service.getKweets(username);
}
#GET
#Path("/{userId}/timeline")
#Consumes(MediaType.TEXT_PLAIN)
#Produces(MediaType.APPLICATION_XML)
public List<Kweet> loadTimeline(#PathParam("userId") int id) {
return service.loadTimeline(id);
}
}
The Error I'm getting is:
HTTP Status 404 - Not Found
type Status report
messageNot Found
descriptionThe requested resource is not available.
GlassFish Server Open Source Edition 5.0
Open your IDEA module settings, and look under Artifacts. You'll find something like this
The highlighted name of the war/exploded artifact is going to be your server context path.
In my case it would become
http://localhost:8080/kwetter-0.0.1
You should replace it with yours.
Now, you need to add the #ApplicationPath path, which is /api. So it becomes
http://localhost:8080/kwetter-0.0.1/api
Now, you need to add the REST service #Path, which is /users. So it becomes
http://localhost:8080/kwetter-0.0.1/api/users
An example:
GET http://localhost:8080/kwetter-0.0.1/api/users/{userId}/followers
Be sure you don't have this checked, under Run/Debug configuration.

Spring Security Basic authentication for a single path next to token authentication

I have a custom ResourceServerTokenServices in place:
#Configuration
public class CloudSecurityConfig {
#Bean
protected MyResourceServerTokenServices() {
return new MyResourceServerTokenServices();
}
}
Then I have follogin ResourceServerConfigurerAdapter:
#Configuration
#EnableWebSecurity
#EnableResourceServer
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityResourceConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);
http.authorizeRequests().accessDecisionManager(accessDecisionManager())
.antMatchers("/h2-console/**").anonymous()
.antMatchers("/health/**").permitAll()
.antMatchers("/v*/api-docs").permitAll().anyRequest()
.authenticated().and().httpBasic().and().headers()
.frameOptions().disable();
}
#Bean
protected UnanimousBased accessDecisionManager() {
List<AccessDecisionVoter<? extends Object>> voterList = new ArrayList<>();
WebExpressionVoter expressionVoter = new WebExpressionVoter();
expressionVoter.setExpressionHandler(new OAuth2WebSecurityExpressionHandler());
voterList.add(expressionVoter);
voterList.add(new AuthenticatedVoter());
return new UnanimousBased(voterList);
}
}
Now I need to add basic authentication (with inMemory credentials) for one single endpoint (lets say /myEndpoint**). How can I achieve this?
Thanks!