I need to mock session with a user when creating the RestAssuredMockMvc
I know that I can add the user while mockMvc.perform, but as the tests are generated, I would like to add a session, with a Principal in it.
At the moment I am doing
mockMvc.perform(post(URL_TEMPLATE, 5L)
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.principal(()-> 2L))
I would like to somehow manage to do it while creating the RestassuredMockMvc
You can use the EXPLICIT mode and start a normal context - that will be faster. Or just use the setup like presented here - https://github.com/rest-assured/rest-assured/wiki/Usage#spring-mvc-authentication (I'm talking about autogenerated tests). You can also use the MockMvc authentication setup if you're using RestDOCS + Spring Cloud Contract WireMock
Related
I am wondering how to set up the netcore dependency container for mvc with one instance per user.
According to https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection#service-lifetimes-and-registration-options there are currently only three methods of specifying a lifetime: singleton(one instance per application), scoped (one instance shared within a HttpRequest), transient (one instance per DI instance request)
Has someone attempted to do create on instance per user yet? I would be curious how it's done - if not i will probably dig through the docs at some point to see how it can be done and share the solution.
Create instance on first user request and keep it alive (for next requests) until with some expiration timeout... This looks like a Sessions.
You may register your service with factory method and analyze current Session inside.
If this is an asp.net core application, middleware that is automatically added to the middleware pipeline handles creating a new DI scope at the start of a request, and disposing of that scope at the end of a request. This scope is stored in HttpContext. This scope will be used when injecting MVC controllers etc. Therefore if you want to have per-user services injected into your MVC controllers / action methods, you'll need to replace this scope in HttpContext with your own one built for the current user. You'd have to do this with middleware which would have to run after the authentication middleware (so after the current user was established). Your custom middleware would look at the current authenticated user, and the GetOrCreate the IServiceProvider (container) held in some cache with probably a sliding expiry. With the per user IServiceProvider in hand, it would then create a scope for the current request and replace the scope currently in HttpContext with this user specific one, also ensuring its disposed of at the end of the request. The thing is, when building the per user container, if you create a new ServiceCollection for each user and register a few services and build and cache that IServiceProvider for that user, you won't be able to resolve any services that you've only registered at the application level I.e on startup. This is where the concept of child containers are handy, which microsoft doesnt implement out of the box, but you can use if you switch to using another DI provider like Autofac. Autofac provides an implementation of IServiceProvider and the ability to spawn child containers. If you used this mechanism you could create a child container for each user, which means it would still be able to resolve all your higher level services, but now you can also resolve the user specific services. If you do all this, you'll be able to have per user services injected.
It's a fair amount of work. If there is enough interest I'd consider adding this feature to my multitenancy library as it already does something similar to create per tenant containers: https://github.com/dazinator/Dotnettency
something like that?
var shoppingLists = new Dictionary < string,
ShoppingListStateContainer > ();
services.AddTransient < ShoppingListStateContainer > (s = >{
var userName = s.GetRequiredService < AuthenticationStateProvider > ().GetAuthenticationStateAsync().GetAwaiter().GetResult().User.Identity.Name ? ?"null";
lock(s) {
if (!shoppingLists.ContainsKey(userName)) shoppingLists.Add(userName, new ShoppingListStateContainer());
}
return shoppingLists[userName];
});
Here's my question: I'm writing a platform which I will be giving to the customers to implement their projects with. So in my platform I have created a SessionService in which I have methods like getCurrentSession, getAttribute, setAttribute, etc. Before spring-session my getCurrentMethod looked like this:
#Override
public HttpSession getCurrentSession() {
if (this.session == null) {
final ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
return attr.getRequest().getSession(true); // true == allow create
}
return this.session;
}
which worked perfectly fine, although it looks ugly and have no backing like redis. Now I want to migrate to spring-session and I was hoping to use the SessionRepository to find the current session of the user, however I can only see a getSession(String id) in there. I believe the id is stored in the cookie, so to use it I will probably have to pass the HttpServletRequest object from my controllers, to my facades, to the service layer which is very near the db layer. This looks like a very bad idea to me, so my question would be: is there any way to get the currentSession near the db layer? One way I would think is to write an interceptor that will be invoked the controllers, which will set the current session in the repository, or the service maybe? I'm just not sure this is the right way to go.
Obtaining the Session Id from Service Layer
You can use the RequestContextHolder to retrieve the session id, set attributes, and remove attributes.
The RequestContextHolder is typically setup using RequestContextListener or RequestContextFilter. Spring Session does NOT work with RequestContextListener because there is no way for Spring Session to wrap the request before the RequestContextListener is invoked.
Unfortunately, this means for Spring Boot applications, RequestContextHolder does not work out of the box. To work around it you can create a RequestContextFilter Bean. See spring-boot/gh-2637 for updates on this issue.
Should I be putting this in session?
Just because it is easy to put a lot of objects in session and it is stored in Redis does not mean it is the right thing to do.
Keep in mind that the entire session is retrieved on every request. So while Redis is fast, this can have a significant impact if there are lots of objects in session. Obviously the implementation can be optimized for your situation, but I think the concept of session generally holds this property.
A general rule of thumb is, "Do I need this object for over 95% of my requests?" (read this as almost all of my requests). If so, it may be a candidate for session. In most cases, the object should be security related if it fits this criteria.
Should I access session id from ThreadLocal in the service layer?
This is certainly open for debate as code is as much of an art as it is a science.
However, I'd argue that you should not be obtaining the session id from thread locale variables throughout your architecture. Doing this feels a bit like obtaining a "Person id" and obtaining the current "Person id" from the HttpServletRequest in a ThreadLocale. Instead, values should be obtained from the controller and passed into your service layer.
Your code does not need changing. It will return the Spring Session session object.
Though it is generally better to inject the HttpSession from the controller, or use session-scoped beans and #SessionAttribute than to have such a session service in the first place.
I am working with Spring Websocket (4.1.4 release) and using #SendToUser for sending messages to the current user. But I've a problem. Ours is a multi-tenant platform where username is not unique, instead a combination of username and tenant id is unique. The DefaultUserSessionRegistry keeps a map from username to a list of session ids:
private final ConcurrentMap<String, Set<String>> userSessionIds = new ConcurrentHashMap<String, Set<String>>();
which would not work in my scenario. So is there a way I can plugin my custom UserSessionRegistry implementation?
After a code search, the issue seems related to this line.
I found that this class is extended by WebSocketMessageBrokerConfigurationSupport, which is extended by a #Configuration class (DelegatingWebSocketMessageBrokerConfiguration), so you could try to extend it by yourself, like in this example:
https://github.com/arawn/overview-of-spring4/blob/master/src/main/java/jco/conference/oxquiz/WebSocketConfig.java
I had no time to verify this, but if your problem is only the UserSessionRegistry implementation, this could be the way of overriding that #Bean method.
Update:
After digging a bit more, I found the real entry point to the whole flow: search for the DefaultHandshakeHandler class, having the determineUser method (I cannot add more links because of my low score)
I am authenticating using LDAP, and everything works fine for users within a specific domain. But I'm having difficulty understanding how I can authenticate users that are under a second domain. My current configuration shown below specifies the first domain in the user-search-base. I removed that parameter, in hopes that it would search all domains, but that didn't work. I also tried specifying the domain as part of the user name when prompted, such as domain\user, but this didn't work either.
<security:authentication-manager alias="authenticationManager">
<security:ldap-authentication-provider
user-search-filter="(samaccountname={0})"
user-search-base="dc=domain,dc=company,dc=com"
user-context-mapper-ref="userContextMapper" >
</security:ldap-authentication-provider>
</security:authentication-manager>
<security:ldap-server
url="ldap://some.url.com:3000"
manager-dn="CN=USER1,OU=FacMgr,OU=FAC,OU=Exchange,dc=domain,dc=company,dc=com"
manager-password="xxxx"/>
Will I need to create a custom search, and if so, can someone provide an example in this context?
It appears as though you're using Active Directory, in which case I wonder why you're not using the more basic ActiveDirectoryLdapAuthenticationProvider class.
At any rate, you should be able to accomplish what you need by extending either LdapAuthenticationProvider or ActiveDirectoryLdapAuthenticationProvider, and passing the appropriate domain to the superclass' method.
Create a constructor which accepts two different LdapAuthenticator objects, and add a second 'try' statement in the doAuthentication method's catch (UsernameNotFoundException notFound) statement (after the check against bad credentials). Use whatever approach you like to get the getAuthenticator method to try the second authenticator if the first one fails.
This approach should work, but if both domains have a username of jsmith, but the user in question resides on the second, you may encounter problems -- that is, this is not a particularly good solution, but it is a solution.
To build this all up properly, use a custom authentication filter (extend the UsernamePasswordAuthenticationFilter), and have the LdapAuthenticationProvider.getAuthenticator() method identify the domain from the value passed by the filter (in your custom login form).
You may need different manager accounts, but this is hopefully enough for you to go on.
The trick to making this work is to use ActiveDirectoryLdapAuthenticationProvider. To do this, just make the following changes:
In resources.groovy:
// Domain 1
ldapAuthProvider1(ActiveDirectoryLdapAuthenticationProvider,
"mydomain.com",
"ldap://mydomain.com/"
)
// Domain 2
ldapAuthProvider2(ActiveDirectoryLdapAuthenticationProvider,
"mydomain2.com",
"ldap://mydomain2.com/"
)
In Config.groovy:
grails.plugin.springsecurity.providerNames = ['ldapAuthProvider1', 'ldapAuthProvider2']
This is all the code you need. You can pretty much remove all other grails.plugin.springsecurity.ldap.* settings in Config.groovy as they don't apply to this AD setup.
Documentation:
http://docs.spring.io/spring-security/site/docs/3.1.x/reference/springsecurity-single.html#ldap-active-directory
I have a question regarding using Spring Security to protect against SQL injection. First of all, I know that use prepared statement can protect from any SQL injection. But In my project I want to show that use Spring Security could help to protect or mitigate against this kind of attack. what i did so far, i made connection using JDBC & Spring and I applied Spring Security and every thing is fine. My question is in my project i used two ways to protect against SQL injection. The first one is Santizing user input and the second one is using Spring Security. I could pass malicious input through Sanitizaing and I want to show that the role of spring security. for example, I pass this input:
TV' UNION SELECT credit_no From credit;--
In this case how I can tell Spring security that it doesnot give any users the credit number. By the way, I used method security level. Just I want to give me an easy way to analyze the user input to see If it has access to data which he asked such as credit.
I hope that clear
Well, your question is not 100% clear, and it may vary on your architecture, but pre post annotations can work well to grab user input.
You can create your own permission evaluator and check permission for pre authorization in your methods.
#PostFilter("hasPermission(filterObject, 'customoperation')")
public CreditCard getCreditCard(String userInput) {
//
}
and your hasPermission method (that you've read about in the link above) goes something like:
public boolean hasPermission(Authentication authentication,
Object target, Object permission) {
if ("customoperation".equals(permission)) {
//your logic here, returning true or false, filtering the object
}
return false;
}
You can also extend the expression handler to use custom functions. Check this answer.