I have a page where accounts with alpha permissions may access. The JSP checks the session for a attribute named "AlphaPerm".
But the problem I'm struggling with is if I find a user is messing/abusing the alpha testing permissions, I want to stop him immediately. I can change his permissions in my database right away but that doesn't stop the abuser right away.
A possible solution is checking my database every time my users do something, But I don't want to do that because that would slow the database down.
So how do I kill his session on-the-fly (Creating a admin page is my plan, but how do I get the users session object)? Basically I want to make a admin page so I can BAN a user.
You can keep references to user sessions by implementing an HttpSessionListener. This example shows how to implement a session counter, but you could also keep references to individual sessions by storing them in a context scoped collection. You could then access the sessions from your admin page, inspect their attributes and invalidate some of them. This post may also have useful info.
Edit: Here's a sample implementation (not tested):
public class MySessionListener implements HttpSessionListener {
static public Map<String, HttpSession> getSessionMap(ServletContext appContext) {
Map<String, HttpSession> sessionMap = (Map<String, HttpSession>) appContext.getAttribute("globalSessionMap");
if (sessionMap == null) {
sessionMap = new ConcurrentHashMap<String, HttpSession>();
appContext.setAttribute("globalSessionMap", sessionMap);
}
return sessionMap;
}
#Override
public void sessionCreated(HttpSessionEvent event) {
Map<String, HttpSession> sessionMap = getSessionMap(event.getSession().getServletContext());
sessionMap.put(event.getSession().getId(), event.getSession());
}
#Override
public void sessionDestroyed(HttpSessionEvent event) {
Map<String, HttpSession> sessionMap = getSessionMap(event.getSession().getServletContext());
sessionMap.remove(event.getSession().getId());
}
}
You can then access the session map from any servlet:
Collection<HttpSession> sessions = MySessionListener.getSessionMap(getServletContext()).values();
As far as I understand your question checking against the DB is definitely a bad thing.
Also you must be comparing some values against some other standard values to decide if the user is messing around.
So an alternate to DB checking you can store these values in the user session and check for those values.
Also instead of creating an Admin page (probably a JSP page) I would suggest using a ServletFilter to do this work.
Also One thing I would personally suggest is instead of invalidating the whole session, you should put some restrictions on the users either for some time or till next login (for example restricting the access of some resource).
Related
I'm having difficulties with authorizing nested accounts in Spring Security. I'm new to Spring Security. I spent around a week to reach a working solution, but it's an ugly one and I'd love to refactor it...
I'm using Spring 4.2.4 and Spring Security 4.0.3.
I have user accounts that look like this:
Office User A
Office User B
Field User C
--> Field Sub-User a
--> Field Sub-User b
Field User D
--> Field Sub-User c
So, an office user has only one account, but a field user has at least one sub-account always, with the potential for two or more sub-accounts. Each sub-account can have different authorities. Like one sub-account can view only, and another sub-account can view plus create.
The user will sign-in with an account (A, B, C, or D). If A or B signs in, there is no issue. However, if user C signs in, they need to pick (a or b) and we need information for their choice. If user D signs in, we need information for user (c). I'm using Spring Security and struggling with getting the information for User a/b/c above. I came to a solution, but it's not ideal, and I'd like to know a more proper way.
My solution:
In the #AuthenticationPrincipal implementation of UserDetails, add below code:
private Collection<GrantedAuthority> authorities;
private String uniqueId1;
private String uniqueId2;
public void setAuthorities(Collection<GrantedAuthority> authorities) {
this.authorities = authorities;
}
public Collection<GrantedAuthority> getAuthorities() {
if (this.authorities != null) {
return this.authorities; //CHILD
}
return super.getAuthorities(); // (SUPER)
}
public void setUniqueId1(String uniqueId1) {
this.uniqueId1 = uniqueId1;
}
public String getUniqueId1() {
if (this.uniqueId1!= null) {
return this.uniqueId1; //CHILD
}
return super.getUniqueId1(); // (SUPER)
}
public void setUniqueId2(String uniqueId2) {
this.uniqueId2 = uniqueId2;
}
public String getUniqueId2() {
if (this.uniqueId2!= null) {
return this.uniqueId2; //CHILD
}
return super.getUniqueId2(); // (SUPER)
}
Then, in my method to get logged-in user information, accept a string of the selected user and do like such:
public #ResponseBody FullUserDetails getLoggedInUserInfo(
#AuthenticationPrincipal MyImplementationOfUserDetails user,
String selectedUsername)
MyImplementationOfUserDetails user2 = getUserInfo(selectedUsername);
user.setAuthorities(user2.getAuthorities());
user.setUniqueId1(user2.getUniqueId1());
user.setUniqueId2(user2.getUniqueId2());
In this way, I am able to 'change' the authorities and unique id properties which would otherwise be unchangeable because they are private in the parent classes and normally only accessible through a constructor. I tried making a new constructor in the UserDetails implementation, but when I create a new #AuthenticationPrincipal, it doesn't override the one in the session. I think a new constructor would be the most proper way to go. How do I override the #AuthenticationPrincipal in the session with a new UserDetails object? Or is there a better approach entirely, which I'm not thinking of? I just want the new authorities and unique ID information for the sub-user that was selected to be put into the #AuthenticationPrincipal. The next time I get the #AuthenticationPrincipal, it will then have that information.
The consequences of not getting the new information and putting it in the #AuthenticationPrincipal is that the webpage behavior will be wrong. Mostly because the authority levels will not be correct for the user that was selected.
I was trying to call:
SecurityContextHolder.getContext().setAuthentication(newAuthenticationObjectHere);
But I wasn't seeing the changes after calling setAuthentication()...
The only way I was able to see the changes was by directly calling setters in the MyImplementationOfUserDetails object retrieved from the #AuthenticationPrinciple.
Sorry, very confused, but the main idea is almost understandable.
I think you go in cycles with an idea to calculate all complex relations between accounts and after that to give the final account required permission and provide access to some resource.
What if to change the logic of providing access to resources without manipulating the account relations? And the very important chain - to use remote/distributed Authorization server like Spring OAuth2 one? With it, you can have authorities for any account AND scopes (!). Depending on organization conditions an account can have different scopes. And your final resources (usually they are controllers methods) have pre-authentication by scope. According to this idea, you can separate the logic of providing access based on specific of accounts, implementing all logic in DB with accounts.
Maybe it's the wrong idea for your project, for me it works - I change scopes for customers depending their conditions, but not manipulate with their data and relations in runtime.
I have an immutable User entity:
public class User {
final LocalDate lastPasswordChangeDate;
// final id, name, email, etc.
}
I need to add a method that will return information if the user's password must be changed i.d. it has not been changed for more than the passwordValidIntervalInDays system setting.
The current approach:
public class UserPasswordService {
private SettingsRepository settingsRepository;
#Inject
public UserPasswordService(SettingsRepository settingsRepository) {
this.settingsRepository = settingsRepository;
}
public boolean passwordMustBeChanged(User user) {
return user.lastPasswordChangeDate.plusDays(
settingsRepository.get().passwordValidIntervalInDays
).isBefore(LocalDate.now());
}
}
The question is how to make the above code more object oriented and avoid the anemic domain model antipattern? Should the passwordMustBeChanged method be moved to User if so how to access SettingsRepository, should it be injected into User's constructor, or should a Settings instance be provided to the ctor, or should the passwordMustBeChanged method require a Settings instance to be provided?
The code of Settings and SettingsRepository is not important, but for completness, here it is:
public class Settings {
int passwordValidIntervalInDays;
public Settings(int passwordValidIntervalInDays) {
this.passwordValidIntervalInDays = passwordValidIntervalInDays;
}
}
public class SettingsRepository {
public Settings get() {
// load the settings from the persistent storage
return new Settings(10);
}
}
For a system-wide password expiration policy your approach is not that bad, as long as your UserPasswordService is a domain service, not an application service. Embedding the password expiration policy within User would be a violation of the SRP IMHO, which is not much better.
You could also consider something like (where the factory was initialized with the correct settings):
PasswordExpirationPolicy policy = passwordExpirationPolicyFactory().createDefault();
boolean mustChangePassword = user.passwordMustBeChanged(policy);
//class User
public boolean passwordMustBeChanged(PasswordExpirationPolicy policy) {
return policy.hasExpired(currentDate, this.lastPasswordChangeDate);
}
If eventually the policy can be specified for individual users then you can simply store policy objects on User.
You could also make use of the ISP with you current design and implement a PasswordExpirationPolicy interface on your UserPasswordService service. That will give you the flexibility of refactoring into real policy objects later on without having to change how the User interacts with the policy.
If you had a Password value object you may also make things slightly more cohesive, by having something like (the password creation date would be embedded in the password VO):
//class User
public boolean passwordMustBeChanged(PasswordExpirationPolicy policy) {
return this.password.hasExpired(policy);
}
just to throw out another possible solution would be to implement a long-running process that could do the expiration check and send a command to a PasswordExpiredHandler that could mark the user with having an expired password.
I have stumbled upon a document that provides an answer to my question:
A common problem in applying DDD is when an entity requires access to data in a repository or other gateway in order to carry out a business operation. One solution is to inject repository dependencies directly into the entity, however this is often frowned upon. One reason for this is because it requires the plain-old-(C#, Java, etc…) objects implementing entities to be part of an application dependency graph. Another reason is that is makes reasoning about the behavior of entities more difficult since the Single-Responsibility Principle is violated. A better solution is to have an application service retrieve the information required by an entity, effectively setting up the execution environment, and provide it to the entity.
http://gorodinski.com/blog/2012/04/14/services-in-domain-driven-design-ddd/
Hello In my web application I am maintaining list of URL authorized for user in a HashMap and compare the requested URL and revert as per the authorization. This Map has Role as key and URLs as value in form of List. My problem is where I should have this Map?
In Session: It may have hundreds of URLs and that can increase the burden of session.
In Cache at Application loading: The URLs may get modified on the fly and then I need to resync it by starting server again.
In Cache that update periodically: Application level Cache that will update periodically.
I require a well optimized approach that can serve the purpose, help me with the same.
I'm preferring to make it as a singleton Class and Have a thread that updates it periodically .. The thread will maintain the state of the cache .. this thread will be started when you get the fist instance of the cache
public class CacheSingleton {
private static CacheSingleton instance = null;
private HashMap<String,Role> authMap;
protected CacheSingleton() {
// Exists only to defeat instantiation.
// Start the thread to maintain Your map
}
public static CacheSingleton getInstance() {
if(instance == null) {
instance = new CacheSingleton();
}
return instance;
}
// Add your cache logic here
// Like getRole,checkURL() ... etc
}
wherever in your code you can get the cached data
CacheSingleton.getInstance().yourMethod();
I want to solve the following problem, it's about deleting entities from a database:
The user selects Delete for a certain entity
The is deleted from the database and disappeared from the list
An undo frame appears inside the page (like Twitter Bootstrap alert messages), where the user can choose to undo the deletion.
I don't know how to realize this, because at the moment I solve this that way:
Delete button links to the URL: delete/entity_id
I have written an if-case for this URL in my request handler that deletes the entity
after the deletion is done, I send a response.sendRedirect(/list) so the updated list is shown
This way I cannot send additional data by redirecting it. Normally I would send the extra data by processing them via the template, but with redirect this is not possible.
How is such a sitation solved?
I have few such scenarios in my web application and here is how I solve it
I have a class called message queue which looks like following
public class MessageQueue {
public static Hashtable<String, Object> messages = new Hashtable<String, Object>();
public static void putMessage(String key, Object obj)
{
messages.put(key, obj);
}
public static Object getMessage(String key)
{
if(key == null)
return null;
Object obj = messages.get(key);
if(obj == null)
return null;
messages.remove(key);
return obj;
}
}
Now this class stays in the memory. Before redirects I create some object that is needed after redirect. Create a random Guid as a String and then store this object in messagequeue
I then add this Guid as a parameter of the URL
String justDeletedId = "someId";
String guid = (new Guid()).toString();
MessageQueue.put(guid,justDeletedId);
sendRedirect("\list\?msgid=" + guid);
Now after redirect you can inspect the messageID and remove the object from the messagequeue and do whatever you please
I choose to allow using this object once ... to avoid memory leak
In the current version ... I also have implemented Last Access Eviction policy which uses a quartz job which cleans up this messagequeue periodically
You could use the setAttribute() and getAttribute() methods of HttpSession. After all that's a way how you can pass Java objects over different HTTP requests.
In your case you could create such an Undo object and store it in the session. After the redirect you have described the session object is retrieved and its content is passed to the template.
I want to get Java HttpSession by JSESSIONID. Is it possible? If yes, how?
You'll basically need to manually collect them all in a Map using a HttpSessionListener yourself.
#WebListener
public class HttpSessionCollector implements HttpSessionListener {
private static final Map<String, HttpSession> SESSIONS = new ConcurrentHashMap<>();
#Override
public void sessionCreated(HttpSessionEvent event) {
HttpSession session = event.getSession();
SESSIONS.put(session.getId(), session);
}
#Override
public void sessionDestroyed(HttpSessionEvent event) {
SESSIONS.remove(event.getSession().getId());
}
public static HttpSession find(String sessionId) {
return SESSIONS.get(sessionId);
}
}
Then, anywhere you want just do HttpSessionCollector.find(sessionId) to get the HttpSession in question.
That said, this is a huge smell. There are certainly better ways to solve the actual functional requirement than this ;) As I commented in your follow-up question:
This is the 2nd time that you asked a question which in real world should never be practiced. Honestly said, this all smells. What is it, the problem for which you think that getting the HttpSession associated with JSESSONID in server side and getting the JSESSIONID value in client side is "the" solution? Elaborate about this in a new question, you'll get answers how to do it the right way.
Take it serious. We're not teasing you, we're just trying to help you in the right direction to avoid that your project/webapp will break due to security holes and bad practices and/or that you will get fired.
You can do it as per BalusC's answer, but the existence of such a facility is a prima facie security breach between different users. You shouldn't be building things like this into your application.
No, the API does not permit this.
I'd say more, but that's about all there is to it.