So, I'm working on a Spring Boot Web App that utilizes Spring Security for login authentication. Currently, we have three types of users who get redirected to the appropriate dashboard and when they try to access the other dashboards through a direct URL, they are denied access. Any unauthenticated user is also denied access to the rest of the site. While testing, I had found that once a user had successfully been authenticated, if they were to use a direct URL to "/", or localhost:8080 for testing, instead of being redirected to the login page as they would when not authenticated, a JSON with information of our tables in our MongoDB instance would be returned. Worse, if they appended a table name to the URL, they would receive the entire table in JSON form.
Example: http://localhost:8080/premios (Currently holding dummy values)
{
"_embedded" : {
"premios" : [ {
"title" : "hdlkfjgd",
"description" : "dflgkj",
"points" : 20,
"enabled" : false,
"_links" : {
"self" : {
"href" : "http://localhost:8080/premios/5a013a974833be43fa38dc53"
},
"premio" : {
"href" : "http://localhost:8080/premios/5a013a974833be43fa38dc53"
}
}
}, {
"title" : "dfdggd",
"description" : "dfgd",
"points" : 5,
"enabled" : false,
"_links" : {
"self" : {
"href" : "http://localhost:8080/premios/5a0a11964833be69a480a901"
},
"premio" : {
"href" : "http://localhost:8080/premios/5a0a11964833be69a480a901"
}
}
}, {
"title" : "alksksjlkakjf",
"description" : "sdlkfkjsdlfkj",
"points" : 5,
"enabled" : false,
"_links" : {
"self" : {
"href" : "http://localhost:8080/premios/5a0a12b24833be6a6e47a22a"
},
"premio" : {
"href" : "http://localhost:8080/premios/5a0a12b24833be6a6e47a22a"
}
}
} ]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/premios{?page,size,sort}",
"templated" : true
},
"profile" : {
"href" : "http://localhost:8080/profile/premios"
},
"search" : {
"href" : "http://localhost:8080/premios/search"
}
},
"page" : {
"size" : 20,
"totalElements" : 3,
"totalPages" : 1,
"number" : 0
}
}
How can I prevent this? Is this due to how I have Spring Security set up, or something I need to do on our mLab to only allow controllers on the backend to make queries? The above premios URL is not a defined request method in any of our controllers so I'm not sure why it's working. Here's how it's configured:
WebSecurityConfig.java
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private SimpleAuthenticationSuccessHandler successHandler;
#Autowired
public void configureGlobal(
AuthenticationManagerBuilder auth,
CustomUserDetailsService userDetailsService) throws Exception {
auth
.userDetailsService(userDetailsService);
}
#Override
protected void configure(HttpSecurity http)
throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/css/**", "/js/**", "/images/**", "/script/**").permitAll()
.antMatchers("/signup").permitAll()
.antMatchers("/webapp/admin").hasRole("ADMIN")
.antMatchers("/webapp/sales").hasRole("SALES")
.antMatchers("/webapp/business").hasRole("USER")
.anyRequest().authenticated()
.and()
.formLogin()
.successHandler(successHandler)
.loginPage("/login")
.permitAll()
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher(("/logout")))
.logoutSuccessUrl("/login")
.permitAll();
}
}
SimpleAuthenticationSuccessHandler.java
#Component
public class SimpleAuthenticationSuccessHandler implements AuthenticationSuccessHandler{
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
#Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
Authentication authentication) throws IOException, ServletException {
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
authorities.forEach(authority -> {
if(authority.getAuthority().equals("ROLE_ADMIN")) {
try {
redirectStrategy.sendRedirect(httpServletRequest, httpServletResponse, "/webapp/admin");
} catch (Exception e) {
e.printStackTrace();
}
}
else if(authority.getAuthority().equals("ROLE_SALES")) {
try {
redirectStrategy.sendRedirect(httpServletRequest, httpServletResponse, "/webapp/sales");
} catch (Exception e) {
e.printStackTrace();
}
}
else if(authority.getAuthority().equals("ROLE_USER")) {
try {
redirectStrategy.sendRedirect(httpServletRequest, httpServletResponse, "/webapp/business");
} catch (Exception e) {
e.printStackTrace();
}
}
else {
throw new IllegalStateException();
}
});
}
}
Maybe, it's something to do with the success handler? I'm new to using Spring Boot and building a Web App so any help is much appreciated!
For anyone with a similar issue, I solved my problem by changing:
.anyRequest().authenticated()
to
.anyRequest().denyAll().
Once a user was authenticated, they were able to make any request of our Web App. By using denyAll, we could prevent all requests that were not specified in our antmatchers. I also modified antmatchers such as this:
.antMatchers("/webapp/business").hasRole("USER")
to
.antMatchers("/webapp/business").access("isFullyAuthenticated() and hasRole('USER')")
And just in case, I made sure to reroute any requests to "/" to our login page "/login".
Related
When i create dslcontracts in my restdoc test with query parameters, it creates the groovy contract file as well as stub file. But when i deploy the contract using #EnableStubRunnerServer, i can never get the query parameters to match.
I realized that the stub file is generated with request looking like:
"request" : {
"url" : "/search",
"method" : "GET",
"queryParameters" : {
"query" : {
"equalTo" : "friday"
}
}
}
However if i change the stub file to :
"request" : {
"urlPathPattern" : "/search",
"method" : "GET",
"queryParameters" : {
"query" : {
"equalTo" : "friday"
}
}
}
it seems to work. Is there a way to make this work?
Here is how i'm writing the test:
#Test
public void searchWithQuery() throws Exception {
Map<String, Object> param = new HashMap<>();
param.put("query", "equalTo(\"friday\")");
mockMvc.perform(get(SEARCH_PATH + "?query=friday"))
.andExpect(status().isOk())
.andDo(document("search-query",
dslContract(param)
));
}
#ClassRule
public static WireMockRule wireMockRule = new WireMockRule(9898);
#Test
public void createXmlFile() {
stubFor(get(urlPathEqualTo("/data/racing/"))
.willReturn(aResponse()
.withBody(loadJSONFile("unibet-demo-input.json"))));
}
I don't know what is going wrong here!
2019-01-16 15:54:05.810 [qtp1929284175-20] INFO ROOT:2341 - RequestHandlerClass from context returned com.github.tomakehurst.wiremock.http.StubRequestHandler. Normalized mapped under returned 'null'
2019-01-16 15:54:05.822 [qtp1929284175-15] INFO __admin:2341 - RequestHandlerClass from context returned com.github.tomakehurst.wiremock.http.AdminRequestHandler. Normalized mapped under returned 'null'
2019-01-16 15:54:05.925 [qtp1929284175-20] ERROR WireMock:40 - Request was not matched as there were no stubs registered:
{
"url" : "/data/racing/",
"absoluteUrl" : "http://localhost:9898/data/racing/",
"method" : "GET",
"clientIp" : "127.0.0.1",
"headers" : {
"User-Agent" : "Jakarta Commons-HttpClient/3.1",
"Host" : "localhost:9898",
"batchID" : "1056178410254123336",
"breadcrumbId" : "ID-SBGML01938-1547654042343-0-1"
},
"cookies" : { },
"browserProxyRequest" : false,
"loggedDate" : 1547654045870,
"bodyAsBase64" : "",
"body" : "",
"scheme" : "http",
"host" : "localhost",
"port" : 9898,
"loggedDateString" : "2019-01-16T15:54:05Z",
"queryParams" : { }
}
Click to see the difference is stating Contents are identical.
com.github.tomakehurst.wiremock.client.VerificationException: A request was unmatched by any stub mapping. Closest stub mapping was: <Click to see difference>
at com.github.tomakehurst.wiremock.client.VerificationException.forSingleUnmatchedRequest(VerificationException.java:43)
at com.github.tomakehurst.wiremock.client.VerificationException.forUnmatchedNearMisses(VerificationException.java:48)
at com.github.tomakehurst.wiremock.junit.WireMockRule.checkForUnmatchedRequests(WireMockRule.java:92)
at com.github.tomakehurst.wiremock.junit.WireMockRule.access$000(WireMockRule.java:34)
at com.github.tomakehurst.wiremock.junit.WireMockRule$1.evaluate(WireMockRule.java:74)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
I had to add wireMockRule on stubFor to make it work.
#ClassRule
public static WireMockRule wireMockRule = new WireMockRule(9898);
#Test
public void createXmlFile() {
wireMockRule.stubFor(get(urlPathEqualTo("/data/racing/"))
.willReturn(aResponse()
.withBody(loadJSONFile("unibet-demo-input.json"))));
}
I've been using Rest-DSL (Camel v2.18.1) and trying to set up my own RestOperationResponseMsgDefinition so as to have a useful API doc. By setting a class to the responseModel to tell which object will be returned in case of success, its structure is properly shown in the API doc. However, if I create a class that has that object within, all endpoints which mention it as their outputType/responseModel stop showing the correct structure in the API doc and put "string" instead. Like this:
My outputType/responseModel:
class Address {
private Integer id;
private String descr;
}
API-doc snippet:
"/addresses" : {
"get" : {
"produces" : [ "application/json" ],
"responses" : {
"200" : {
"description" : "Success.",
"schema" : {
"$ref" : "#/definitions/Address"
}
}
...
In Swagger-UI, the response example value is shown as:
{
"id": "string",
"descr": "string"
}
Everything is alright till I create any class having an Address object within! For instance:
class Store {
private Integer id;
private String name;
private Address address;
}
Now, for the same endpoint mentioned before, I get...
"/addresses" : {
"get" : {
"produces" : [ "application/json" ],
"responses" : {
"200" : {
"description" : "Success.",
"schema" : {
"type" : "string",
"format" : "com.mycompany.integration.domain.Address"
}
}
...
And the following in Swagger-UI as example value:
"string"
Has anybody ever passed through and solved this? This seems a bug, though...
I have a simple API for a game tip website:
/class is the endpoint for in game classes
/tip is the endpoints for the tips
/user is the endpoint for the users
Each tip has 3 relations:
(:User)-[:AUTHORED]-(:Tip)
(:Class)<-[:FOR]-(:Tip)
(:Class)<-[:AGAINST]-(:Tip)
When I create a Tip using POST, I do'nt know how to add relations at the create time.
I can do this way: Add relation to another node in SDN4 + REST after creating the resource, but I want to do it with only one query.
EDIT:
I tried to POST this:
'{"content":"TEST", "forClass":"/class/2", "againstClass":"/class/2"}'
and the item has been created, no InvalidArgument Exception raised, but if I go to my class resource's tips, I don't have any tips:
GET /class/2/tips:
{
"_embedded" : {
"tip" : [ ]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/class/2/tips"
}
}
}
GET /tip/9 (the created one):
{
"content" : "TEST",
"_links" : {
"self" : {
"href" : "http://localhost:8080/tip/9"
},
"tip" : {
"href" : "http://localhost:8080/tip/9"
},
"author" : {
"href" : "http://localhost:8080/tip/9/author"
},
"againstClass" : {
"href" : "http://localhost:8080/tip/9/againstClass"
},
"forClass" : {
"href" : "http://localhost:8080/tip/9/forClass"
}
}
}
GET /tip/9/forClass:
{
"name" : null,
"_links" : {
"self" : {
"href" : "http://localhost:8080/class/2"
},
"bnSClass" : {
"href" : "http://localhost:8080/class/2"
},
"tips" : {
"href" : "http://localhost:8080/class/2/tips"
}
}
}
Hi i am using mongodb with springboot and not able to fetch records on the basis of #DBRef. My scenerio is:
I have AuthenticationToken Collection and User collection as follows:
{
"_id" : ObjectId("556bdfc2ccf2e6509f8a2849"),
"_class" : "com.samepinch.domain.user.AuthenticationToken",
"token" : "2efd1cfe-2f2f-4163-b500-bac6e4654287",
"createdDate" : ISODate("2015-06-01T04:29:54.364Z"),
"updatedDate" : ISODate("2015-06-01T04:29:54.364Z"),
"user" : DBRef("users", ObjectId("556bdfc2ccf2e6509f8a2848"))
}
And User
{
"_id" : ObjectId("556bdfc2ccf2e6509f8a2848"),
"_class" : "com.samepinch.domain.user.User",
"age" : 0,
"username" : "abc#yahoo.com",
"roles" : [
"ROLE_USER"
],
"firstName" : "abc",
"lastName" : "mno",
"email" : "abc#yahoo.com",
"gender" : "male",
"isAccountLocked" : false,
"prefAgeFrom" : 0,
"prefAgeTo" : 0,
"notificationNewMatch" : true,
"notificationMessage" : true,
"createdDate" : ISODate("2015-06-01T04:29:54.325Z"),
"updatedDate" : ISODate("2015-06-01T04:29:54.325Z")
}
Now i want to get Authentication token on the basis of user id in authentication collection.
I am using Mongo Repository to fetch AuthenticationToken on the basis of user id but it is not working.
To fetch AuthenticationToken
Step 1
public AuthenticationToken findByUserId(String userId){
ObjectId objId = new ObjectId(userId);
return authRepository.findByUserId(objId);
}
Step 2
public interface AuthenticationTokenRepository extends MongoRepository<AuthenticationToken, String> {
AuthenticationToken save(AuthenticationToken token);
AuthenticationToken findByToken(String token);
#Query("{'user._id' : ?0}")
AuthenticationToken findByUserId(ObjectId objId);
}
I am following above steps to fetch AuthenticationToken from DB but getting null. Previously it was working fine when i was not using #DBRef over User in Authentication Domain.
AuthenticationToken
public class AuthenticationToken extends BaseEntity{
#JsonProperty
String token;
#DBRef
User user;
public AuthenticationToken(String token,User user){
this.token = token;
this.user = user;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
}
This is not big deal,use spring data mongodb criteria like
Query query = new Query(Criteria.where("user.$id").is(new ObjectId(userId)));
AuthenticationToken token = mongoTemplate.findOne(query, AuthenticationToken.class);