I am simply trying to check whether a given user has a given WebSphere administrative role, within a Java servlet.
The idiom:
HttpServletRequest#isUserInRole
... works for non-administrative roles, and the iscadmins administrative role defined in this documentation page.
However, all other roles in the page above (which seem to differ from iscadmins, scope-aside, by having their first letter capitalized) are not reflected when invoking isUserInRole.
I've tried checking both with the primary administrative user (file-based, created with the profile) and with other users whom I've explicitly added administrative roles to.
In all cases, only iscadmin role checks return true when assigned.
Using standard WAS 8.5.5 if that's any relevant.
I am wondering whether there is something crucial I misunderstand about security and scope in this context.
Note
I have tried different combinations to check for role names that have a first capitalized letter: as is, lowercase, all-caps, etc. even got more creative with the Admin Security Manager role...
After hours and hours of headaches and searches through undocumented APIs, I think I've found what I'm looking for.
Fair warning
I couldn't find any documentation about this, not even javadocs.
I cannot honestly tell if this is the recommended approach.
This said, the approach below works for me (tested by assigning and removing the Admin security manager role from the logged on user, then reloading the servlet and debugging).
Also, the mistery remains on why these roles are not visible through the HttpServletRequest#isUserInRole idiom.
Code recipe
// relevant imports
import com.ibm.websphere.management.authorizer.AdminAuthorizer;
import com.ibm.websphere.management.authorizer.AdminAuthorizerFactory;
import static com.ibm.ws.security.util.Constants.*;
// you'll need the com.ibm.ws.admin.core.jar plugin in your classpath for this
AdminAuthorizer aa = AdminAuthorizerFactory.getAdminAuthorizer();
// all admin roles are there as constants,
// save for "iscadmins", which you can retrieve with
// the HttpServletRequest#isUserInRole idiom anyway
String role = com.ibm.ws.security.util.Constants.ADMINSECURITY_ROLE;
// that's it!
boolean test = aa.isCallerInRole(role);
Related
I'm trying to set up my website to allow location additions to the urls.
EG: mysite.com/us/ca/sanfrancisco/home
While also still allowing mysite.com/home and everything in between.
Spring boot parent so you know what version of spring I'm using:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
</parent>
If there's another piece of versioning you need, let me know.
I get that I can add in regex variables to the request mapping, but how would I go about persisting those urls across more requests?
So right now for an example, the testing error page I have:
#RequestMapping({"/error/501", "/{state:[a-z]{2}}/error/501", "/{state:[a-z]{2}}/{city:[a-z]+}/error/501"})
public ModelAndView testingLocations(ModelMap model, #PathVariable(value="state", required = false) String state,
#PathVariable(value="city", required=false) String city){
getLogger().info("State: {}", state);
model.addAttribute("stateTest",state+":"+city);
model.addAttribute("view", "error");
return new ModelAndView("error/501", model);
}
But when I'm on my testing page, and I click the home button, it takes me back to mysite.com/home
So My Questions
Is there a way for me to persist it so that if they're currently on a location based url, it will apply that base to the future navigations? (unless they manually enter the url to not include them)
Then as a follow-up, is there a way for me to globally apply these request variables without requiring me to add the #PathVariable to every request mapping method? I get that I can just add the request mapping variable strings themselves to the controller class, so that I don't need those on every method. But is there a way for me to utilize those without needing the #PathVariable annotations?
Finally, is there a way for me to make this not as hardcoded, like a way for me to say /{*location}/error to cover as deep as the locations will allow? While still having the verification on the location formatting, so verifying that 1 we support the locations given, 2 the format is correct (/ca/sanfrancisco vs /anything/anything
The last one I can live with, if I need to have the /state/city/municipality/actualtarget
As far as verifying that we support the locations given, I understand that's on my end, which I'll probably just have a small database to keep track of where we do and do not support for the given variables.
Is there a best practice for building this system? I tried to find something on this, but googling "spring boot location url" is not the best at giving me what I need, since "location" can apply to a pretty wide range of topics. I've gotten to where I am from searching, but I can't seem to pin down these last few steps.
Any help/advice/suggestions is appreciated. If upgrading versions is required, I'm not sure how viable that is at the moment, I'd have to look into it. Preferably I'd like the solution to be able to be done on the current spring version I'm running.
The best way here is:
#RequestMapping("/some/{foo}/{baz}")
public String hi(CompositeObject compositeObject) {
return "hi";
}
#Data
public class CompositeObject {
private String foo;
private String baz;
}
Spring provides functionality for request path and request parameters to collect it into a composite object. It doesn' work either with body or headers.
If you have something optional like state, then just keep it null at the controller and handle later
I'm a newbie in Liferay and I'm creating a hook to authenticate using a expando column instead of an email address.
My authentication class works fine, but one problem still remains:
After a successful authentication, I must redirect the page to the user's public or private page (any of theese is enough for me)
I followed the common of instructions for this on any forum on Internet:
Create a class that extends com.liferay.portal.kernel.events.Action and do the logic there. In my case, my class is named CustomPostLoginAction
Modify portal.properties adding the entries
login.events.post=com.liferay.sample.hook.action.CustomPostLoginAction
auth.forward.by.last.path=true
default.landing.page.path=/web/guest/home
Redeploy and "voilá"
When I reboot my web server, everything is fine, but when I run my hook using any browser, once I get successfully authenticated, it stills showing me the default login error messages. When I check my console, I found that my action class is never called and no special action is executed after my authentication class. So I have the following questions:
Where can I found an example to class to be used as a value for the property "auth.pipeline.post" if needed?
On the method authenticateByEmailAddress on my authentication class, the last argument is a java.util.Map containing parameters like "doActionAfterLogin", "redirect", "structsAction", etc. Do I get something if I assign values to those keys on that map? If yes, where can I found an example of valid values to assign to each one of them?
Do I have to change something in my custom login page? (it works, but still I have to ask this)
Is it necessary to work with the class DefaultLandingPageAction? If yes, how can I do it? Because I have only the portal's bytecodes (.class)
And most important: What am I doing wrong?
For the record:
I'm using Liferay 6.1 bundle with Tomcat 7 and SDK included with Liferay's default database.
If any of you need to watch any of my source code and/or properties files, just let me know and I will publish them.
Thanks in advance to all of you.
I can't add a comment to your original post so I'm gonna have to post an answer to ask you for some additional information (will update my answer accordingly).
Did you modify portal.properties directly or did you create a new portal.properties inside your hook?
Once you extended com.liferay.portal.kernel.events.Action, did you override the run method?
I'm working on a Java-based web app using Tomcat 7.0 as the application server. After the helpful responses to a prior question, I've decided to use bcrypt to securely store passwords in my HSQLDB. However Tomcat's default Realm implementations can't handle bcrypt, so I need to write my own; that's the only reason I'm writing a custom realm though as in all other ways plain JDBCRealm would work. I've been googling and looking at examples and I'm rather confused on a couple of points.
First, should I extend RealmBase, or JDBCRealm? Most examples I found use RealmBase, but I've successfully been using JDBCRealm for the app up to this point (as it's still in development I started off with storing the passwords in plaintext and just using JDBCRealm to handle authentication), and one answer to a question on Code Ranch recommended just extending that. I'm not exactly sure which methods I'd need to override in that case, though. Just the authenticate method, or something more? If did this would JDBCRealm still be able to handle and manage user roles, getPrincipal, and all that?
Second, in the CodeRanch example linked above, unless I'm missing something, the getPassword method seems to be returning the unencrypted password. Since I'm going to be using bcrypt that won't be possible, and it seems kind of inadvisable anyway, I would think. In other examples like on this blog post, getPassword seems to just return the password directly from the database. So which way is correct? I can't find what exactly getPassword is used for; the documentation doesn't say. Will it be ok to just return the encrypted value stored in the database for this?
If anybody can tell me what class I should extend, what methods I should override, and what getPassword should return, I would really appreciate it.
Well after some trial and error I figured out how to do this. I extended JDBCRealm and only overrode the authenticate method and it works perfectly. I put BCrypt.java in the same directory as my custom realm, and this code is what worked:
import java.security.Principal;
import org.apache.catalina.realm.JDBCRealm;
public class BCryptRealm extends JDBCRealm
{
#Override
public Principal authenticate(String username, String credentials)
{
String hashedPassword = getPassword(username);
// Added this check after discovering checkpw generates a null pointer
// error if the hashedPassword is null, which happens when the user doesn't
// exist. I'm assuming returning null immediately would be bad practice as
// it would let an attacker know which users do and don't exist, so I added
// a call to hashpw. No idea if that completely solves the problem, so if
// your application has more stringent security needs this should be
// investigated further.
if (hashedPassword == null)
{
BCrypt.hashpw("fakePassword", BCrypt.gensalt());
return null;
}
if (BCrypt.checkpw(credentials, hashedPassword))
{
return getPrincipal(username);
}
return null;
}
}
I'm trying to find a solution for configuring a server-side Java application such that different users of the system interact with the system as if it were configured differently (Multitenancy). For example, when my application services a request from user1, I wish my application to respond in Klingon, but for all other users I want it to reply in English. (I've picked a deliberately absurd example, to avoid specifics: the important thing is that I want the app to behave differently for different requests).
Ideally there's a generic solution (i.e. one that allows me to add
user-specific overrides to any part of my config without having to change code).
I've had a look at Apache Commons Configuration which has built in support for multitenant configuration, but as far as I can tell this is done by combining some base config with some set of overrides. This means that I'd have a config specifying:
application.lang=english
and, say a user1.properties override file:
application.lang=klingon
Unfortunately it's much easier for our support team if they can see all related configurations in one place, with overrides specified somehow inline, rather than having separate files for base vs. overrides.
I think some combination of Commons Config's multitenancy + something like a Velocity template to describe the conditional elements within underlying config is kind of what I'm aiming for - Commons Config for the ease of interacting with my configuration and Velocity for very expressively describing any overrides, in a single configuration, e.g.:
#if ($user=="user1")
application.lang=klingon
#else
application.lang=english
#end
What solutions are people using for this kind of problem?
Is it acceptable for you to code each server operation like in the following?
void op1(String username, ...)
{
String userScope = getConfigurationScopeForUser(username);
String language = cfg.lookupString(userScope, "language");
int fontSize = cfg.lookupInt(userScope, "font_size");
... // business logic expressed in terms of language and fontSize
}
(The above pseudocode assumes the name of a user is passed as a parameter, but you might pass it via another mechanism, for example, thread-local storage.)
If the above is acceptable, then Config4* could satisfy your requirements. Using Config4*, the getConfigurationScopeForUser() method used in the above pseudocode can be implemented as follows (this assumes cfg is a Configuration object that has been previously initialized by parsing a configuration file):
String getConfigurationScopeForUser(String username)
{
if (cfg.type("user", username) == Configuration.CFG_SCOPE) {
return Configuration.mergeNames("user", username);
} else {
return "user.default";
}
}
Here is a sample configuration file to work with the above. Most users get their configuration from the "user.default" scope, but Mary and John have their own overrides of some of those default values:
user.default {
language = "English";
font_size = "12";
# ... many other configuration settings
}
user.John {
#copyFrom "user.default";
language = "Klingon"; # override a default value
}
user.Mary {
#copyFrom "user.default";
font_size = "18"; # override a default value
}
If the above sounds like it might meet your needs, then I suggest you read Chapters 2 and 3 of the "Getting Started Guide" to get a good-enough understanding of the Config4* syntax and API to be able to confirm/refute the suitability of Config4* for your needs. You can find that documentation on the Config4* website.
Disclaimer: I am the maintainer of Config4*.
Edit: I am providing more details in response to comments by bacar.
I have not put Config4* in a Maven repository. However, it is trivial to build Config4* with its bundled Ant build file, because Config4* does not have any dependencies on third-party libraries.
Another approach for using Config4* in a server application (prompted by a comment by bacar) with Config4* is follows...
Implement each server operation like in the following pseudo-code:
void op1(String username, ...)
{
Configuration cfg = getConfigurationForUser(username);
String language = cfg.lookupString("settings", "language");
int fontSize = cfg.lookupInt("settings", "font_size");
... // business logic expressed in terms of language and fontSize
}
The getConfigurationForUser() method used above can be implemented as shown in the following pseudocode:
HashMap<String,Configuration> map = new HashMap<String,Configuration>();
synchronized String getConfigurationForUser(String username)
{
Configuration cfg = map.get(username);
if (cfg == null) {
// Create a config object tailored for the user & add to the map
cfg = Configuration.create();
cfg.insertString("", "user", username); // in global scope
cfg.parse("/path/to/file.cfg");
map.put(username, cfg);
}
return cfg;
}
Here is a sample configuration file to work with the above.
user ?= ""; // will be set via insertString()
settings {
#if (user #in ["John", "Sam", "Jane"]) {
language = "Klingon";
} #else {
language = "English";
}
#if (user == "Mary") {
font_size = "12";
} #else {
font_size = "10";
}
... # many other configuration settings
}
The main comments I have on the two approaches are as follows:
The first approach (one Configuration object that contains lots of variables and scopes) is likely to use slightly less memory than the second approach (many Configuration objects, each with a small number of variables). But my guess is that the memory usage of either approach will be measured in KB or tens of KB, and this will be insignificant compared to the overall memory footprint of your server application.
I prefer the first approach because a single Configuration object is initialized just once, and then it is accessed via read-only lookup()-style operations. This means you don't have to worry about synchronizing access to the Configuration object, even if your server application is multi-threaded. In contrast, the second approach requires you to synchronize access to the HashMap if your server application is multi-threaded.
The overhead of a lookup()-style operation is in the order of, say, nanoseconds or microseconds, while the overhead of parsing a configuration file is in the order of, say, milliseconds or tens of milliseconds (depending on the size of the file). The first approach performs that relatively expensive parsing of a configuration file only once, and that is done in the initialization of the application. In contrast, the second approach performs that relatively expensive parsing of a configuration file "N" times (once for each of "N" users), and that repeated expense occurs while the server is processing requests from clients. That performance hit may or may not be an issue for your application.
I think ease of use is more important than ease of implementation. So, if you feel that the second approach will make it easier to maintain the configuration file, then I suggest you use that approach.
In the second approach, you may wonder why I put most of the variables in a named scope (settings) rather than in the global scope along with the "injected" user variable. I did that for a reason that is outside the scope of your question: separating the "injected" variables from the application-visible variables makes it easier to perform schema validation on the application-visible variables.
Normally user profiles are going into a DB and the user must open a session with a login. The user name may go into the HTTPSession (=Cookies) and on every request the server will get the user name and may read the profile from the DB. Shure, the DB can be some config files like joe.properties, jim.properties, admin.properties, etc.
I'm trying to make a simple forum just to get the hang of the Spring Security and MVC frameworks.
For simplicity's sake, let's I have a JSP to view a forum post, which looks like the following:
<body>
...
Title: ${forumPost.title} <br>
Author: ${forumPost.author.name} <br>
Message: {forumPost.message} <br>
<security:authorize ifAnyGranted="ROLE_ADMIN">
Edit: Edit
</security:authorize>
...
</body>
My problem is: not only should an Administrator be able to edit this post, but the original author should be able to as well. Therefore, I only want ROLE_ADMIN and the original author to be able to see the Edit link. However I'm not sure how to filter by user with the security:authorize tag, or if I'll need to go about this a different way.
Any suggestions would be much appreciated. Thanks!
Assuming that you have a controller that sits behind this page, I would simply add a canEditPost field to the ModelAndView that looks something like (semi-pseudocode):
private boolean isAdmin() {
Authentication currentAuthObj = SecurityContextHolder.getContext().getAuthentication();
List<GrantedAuthority> authorities = Arrays.asList(currentAuthObj.getAuthorites());
for (GrantedAuthority auth : authorities) {
if ("ROLE_ADMIN".equals(auth.getAuthority())) {
return true;
}
}
return false;
}
boolean currentUserIsAuthor = ...;
modelAndView.addObject("canEditPost",
Boolean.valueOf(currentUserIsAuthor || isAdmin());
And then in your view just reference $canEditPost.
It's generally better for the view to just reference a simple flag in the model than have the view/template doing the actual logic.
Does your Author object implement equals in such a way that each author is unique?
If so, you could simply check if the Author is the same as the current user (You'd have two sets of tags).
you can have conditions
<% if(mycondition.isTrue()){ %>
<security:authorize ifAnyGranted="ROLE_ADMIN">
Edit: Edit
</security:author
<% }%>
#matt b's answer is a great way to do it and is probably what I'll end up doing. But I found another way that is a bit more complicated but will achieve what I put in this post.
I did a bit of reading and found out that you can handle security at the domain object level and essentially give read/write/delete privileges to a role or to an arbitrary object, for example, the current user ID. In this example, I would give the current user id access to a domain object, in this case a ForumPost object that has its own unique id from the database.
The current user id would then be granted read and write access, which can (via the XML configuration) be defined as a custom role of sorts (I believe the correct term is actually Voter). I could then name this voter MESSAGE__EDIT.
So, in my JSP I could then use the following:
security:authorize ifAnyGranted="MESSAGE_EDIT"
And it would (again, through XML configuration) get the current user id and give access based on the current domain object, in this case, a ForumPost object.
It is a fair bit more work than it sounds, but it can definitely be done.
Some documentation on all this can be found in the Domain Object Security section in the Spring Security Reference Documentation (http://static.springframework.org/spring-security/site/reference/html/springsecurity.html (for some reason the link to the Domain object Security section is broken for now)).