How do you create a subclass of PropertySourcesPropertyResolver in spring 4? - spring

I'm trying to figure out a way to store certain properties in an encrypted form while they are at rest, and have them transparently decrypted before the property is injected into any beans, whether they are using #Value or they are defined in xml by setting properties. We're not using spring-boot yet. The property file would look like this:
db_password={aes}some_encrypted_value
I can see in the logs where the PropertySourcesPropertyResolver gets the value for my property. It should be pretty simple to create my own implementation of the PropertySourcesPropertyResolver.getProperty method that looks for the "{aes}" prefix, decrypting it if necessary, but I can't figure out how to use my subclass in my application.
Does anyone have any idea how I can get spring to use my implementation instead of Springs?
I initially tried to use the PropertySourcesPlaceholderConfigurer that worked for me in Spring 3, but I couldn't figure out how to make it work in spring 4. I also couldn't get the newer PropertySourcesPlaceholderConfigurer to work either.
Can anyone point me in the right direction?

We did it as follows with Spring 4.0.3 RELEASE
public class MyPropertyConfigurer extends PropertyPlaceHolderConfigurer{
protected void convertProperties(Properties props){
Enumeration<?> propertyNames = props.propertyNames();
while(propertyNames.hasMoreElements()){
String propName = (String)propertyNames.nextElement();
String propValue = (String)props.getProperty(propName);
if(propName.indexOf("db_password") != -1){
setPropertyValue(props,propName,propValue);
}
}
}
private void setPropertyValue(Properties props,String propName,String propValue){
String decryptedValue = PasswordUtility.decrypt(propValue);
props.setProperty(propName,decryptedValue);
}
}
In xml, it was configured as below
<bean id="dbPropertyPlaceholder" class="mypackage.MyPropertyConfigurer">
<property name="locations">
<list>
<value>file:myProp.properties</value>
<list>
</property>
</bean>

Related

How to parse spring security expressions programmatically (e.g. in some controller)

How do you parse spring (web) security expressions like hasRole('admin') programmatically (without using tags, annotations or ...)? (reference doc)
I've found Spring: What parser to use to parse security expressions - but I don't know how to find or build the EvaluationContext e.g. inside a spring controller.
Without providing an EvaluationContext gives
org.springframework.expression.spel.SpelEvaluationException: EL1011E:(pos 0): Method call: Attempted to call method hasRole(java.lang.String) on null context object
you need to add several things in order to get this thing working. You have to plug into the Spring's security API. Here's how I did it and it is working fine with Spring 3.2.
First as it was stated before you must have similar configuration in your spring-context.xml:
<security:http access-decision-manager-ref="customAccessDecisionManagerBean">
<security:http/>
<bean id="customWebSecurityExpressionHandler"
class="com.boyan.security.CustomWebSecurityExpressionHandler"/>
<bean id="customAccessDecisionManagerBean"
class="org.springframework.security.access.vote.AffirmativeBased">
<property name="decisionVoters">
<list>
<bean class="org.springframework.security.web.access.expression.WebExpressionVoter">
<property name="expressionHandler" ref="customWebSecurityExpressionHandler" />
</bean>
</list>
</property>
</bean>
This defines a new expressionHandler to override the default one for the WebExpressionVoter. Then we add this new decision voter to the decision manager. CustomWebSecurityExpressionHandler's purpose it to control the creation of SecurityExpressionRoot. So far so good. The question is why do you need a CustomWebSecurityExpressionRoot and the answer is simple as that - you define your custom security methods there. Having this in mind we can write the following classes:
public class CustomWebSecurityExpressionHandler extends DefaultWebSecurityExpressionHandler {
#Override
protected SecurityExpressionOperations createSecurityExpressionRoot(
Authentication authentication, FilterInvocation fi) {
CustomWebSecurityExpressionRoot expressionRoot =
new CustomWebSecurityExpressionRoot(authentication, delegationEvaluator);
return expressionRoot;
}
}
}
public class CustomWebSecurityExpressionRoot extends WebSecurityExpressionRoot {
public CustomWebSecurityExpressionRoot(Authentication auth, FilterInvocation fi) {
super(auth, fi);
}
// in here you must define all of the methods you are going to invoke in #PreAuthorize
// for example if you have an expression with #PreAuthorize('isBoyan(John)')
// then you must have the following method defined here:
public boolean isBoyan(String value) {
//your logic goes in here
return "Boyan".equalsIgnoreCase(value);
}
}
If you want to get a reference to the ExpressionParser you can use the following method AbstractSecurityExpressionHandler.getExpressionParser(). It is accessible through CustomWebSecurityExpressionHandler. Also you can take a look at its API if you want to do something more specific.
I hope this answers you question.

Call certain methods alone in a class using spring/pojo?

I am implementing a health check for my application.I have configured the classes for different logical systems in our application and have written methods which check for conditions across the environment like db count , logging errors , cpu process etc.
Now I have requirement where I have to check only certain conditions ie certain methods in the class according to the host.
What is the best way to access those methods via property file ? Please give your suggestions.
Thanks.
I don't like using reflection for this sort of thing. Its too easy for the property files to be changed and then the system starts generating funky error messages.
I prefer something straightforward like:
controlCheck.properties:
dbCount=true
logger=false
cpuProcess=true
Then the code is sort of like this (not real code):
Properties props = ... read property file
boolean isDbCount = getBoolean(props, "dbCount"); // returns false if prop not found
... repeat for all others ...
CheckUtilities.message("Version " + version); // Be sure status show version of this code.
if (isDbCount) {
CheckUtilities.checkDbCount(); // logs all statuses
}
if (... other properties one by one ...) {
... run the corresponding check ...
}
There are lots of ways to do it but this is simple and pretty much foolproof. All the configuration takes place in one properties file and all the code is in one place and easy for a Java programmer to comment out tests that are not relevant or to add new tests. If you add a new test, it doesn't automatically get run everywhere so you can roll it out on your own schedule and you can add a new test with a simple shell script, if you like that.
If its not running a particular test when you think it should, there's only two things to check:
Is it in the properties file?
Is the version of the code correct?
You can define different beans for every check you need:
<bean id="dbcountBean" class="DBCountHealtCheck" scope="prototype">
<!-- bean properties -->
</bean>
Then a bean for HealtCheck with operations bean injected:
<bean id="healtChecker" class="HealtChecker" scope="prototype">
<property name="activeChecker"><bean class="PropertiesFactoryBean>
<property name="location">file:path/to/file</property></bean>
</property>
<property name="dbCountCheck" ref="dbCountBean" />
<!-- other properties -->
</bean>
class HealtChecker {
private DBCountHealtCheck dbCountChecker;
private Properties activeChecker;
public void setDbcount(DBCountHealtCheck dbCountChecker) {
this.dbCountChecker = dbCountChecker;
}
public void setActiveChecker(Properties activeChecker) {
this.activeChecker = activeChecker;
}
public void check() {
if("true".equals(this.activeChecker.get("dbCount")) {
this.dbCountChecker.check();
}
}
If with this solution you can't reload file, in HealthChecker remove activeChecker a property public void setPropertiesLocation(URL propertiesLocation); let HealthChecker implements InitializingBean and load properties in afterPropertiesSet()

reading values from XML and displaying them in JSP

I have some experience with JSF but I want to learn some Spring MVC now. I wish to display the options to the user to change the language my website is displayed in. To accomplish this I want to define the languages in XML and set them in a bean, then in a JSP iterate over that list to show the languages options to the user.
This is what my XML looks like:
<bean id="languagesSupportedBean" class="be.maxcorp.Util.LanguageBean">
<property name="languagesSupported">
<array>
<value>en</value>
<value>nl</value>
</array>
</property>
</bean>
This is my LanguagesSupportedBean class:
#Component
public class LanguageBean {
public String[] languagesSupported;
public String[] getLanguagesSupported() {
return languagesSupported;
}
public void setLanguagesSupported(String[] languagesSupported) {
this.languagesSupported = languagesSupported;
}
}
In my JSP I'd like to do something like this:
<c:forEach items="${languageBean.LanguagesSupported}" var="language">
${language}
</c:forEach>
Because Spring MVC is request-based and not component-based I suppose this approach won't work unless I add the LanguageBean as attribute to every Model param in every controller method?
I'd greatly appreciate any tips on accomplishing this.
If you're using an InternalResourceViewResolver you should be able to set a property called exposeContextBeansAsAttributes that will expose your beans as attributes that JSPs can access directly:
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="exposeContextBeansAsAttributes" value="true"/>
</bean>
So if your LanguageBean is specified as id="languagesSupportedBean" in your XML, you can reference it directly in your JSP using its id:
<c:forEach items="${languagesSupportedBean.languagesSupported}" var="language">
${language}
</c:forEach>
So no controller or model modifications needed.
If you are declaring your LanguageBean in XML, then you won't need to annotate it #Component
Alternatively, if you're not using InternalResourceViewResolver you could inject your LanguageBean into your controller and then expose it using a method annotated #ModelAttribute:
#ModelAttribute("languagesSupportedBean")
public LanguageBean getLanguageBean() {
return languageBean;
}
That would then be accessible in your JSP using the name languagesSupportedBean and would alleviate the need to set the bean on every model in every controller method.
Store the bean in the session. You can access it the same way from the JSP. Otherwise you can extend Model and #Autowire your been there(not sure that it will work).

Reading a "properties" file

I have a Rest service using Resteasy (running on top of Appengine), with the following psuedo code:
#Path("/service")
public class MyService {
#GET
#Path("/start")
public Response startService() {
// Need to read properties file here.
// like: servletContext.getResourceAsStream("/WEB-INF/config.properties")
}
}
However its obvious that the servlet context cannot be accessed here.
And code like:
InputStream inputStream = this.getClass().getClassLoader()
.getResourceAsStream("/WEB-INF/config.properties");
Can't be executed within the Appengine environment.
EDIT:
I have tried doing it with Spring like:
appContext.xml
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations" value="/WEB-INF/auth.properties"/>
</bean>
Then, put this on the actual class fields:
#Path("/service")
public MyService{
#Autowired
#Value("${myservice.userid}")
private String username;
#Autowired
#Value("${myservice.passwd}")
private String password;
// Code omitted
}
However, part of the code of the MyService complains because the username and password was not "injected", I mean its empty although its on the auth.properties file
In RESTEasy you can easily inject Servlet context via #Context annotation: http://docs.jboss.org/resteasy/docs/2.3.1.GA/userguide/html_single/index.html#_Context
Examples can be found here: Rest easy and init params - how to access?
This should work if you put the file in /WEB-INF/classes/ (which, importantly, is on the classpath), specifying config.properties as a file at the top-level.
this.getClass().getClassLoader().getResourceAsStream("/config.properties");
See this similar question: How to load properties file in Google App Engine?
Edit: Now you've edited, I'll respond & answer the Spring-related question. So, put the auth.properties into /WEB-INF/classes/ , and then specify classpath as follows.
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:auth.properties"/>
</bean>

Adding custom RequestCondition's in Spring mvc 3.1

I have a Spring mvc (3.1.1) app, and I want to define conditions beyond what's available in RequestMapping. I have a couple of things I want to use it for.
First, it would be nice if I could show a different home page for different user types:
#Controller
public class HomepageController {
#RequestMapping(value = "/")
#CustomCondition(roles = Guest.class)
public String guestHome() { /*...*/ }
#RequestMapping(value = "/")
#CustomCondition(roles = Admin.class)
public String adminHome() { /*...*/ }
}
Second, I want the app to function both as a web site and as a REST service (e.g. for mobile apps), so I'd want to let the website access both html and json actions, and let the service (different subdomain) only access json actions (some kind of #CustomCondition(web = true) which only matches website urls)
Can this work for any of the two uses I'm planning?
I found very little documentation about custom conditions, but I did find one example that implements custom conditions which might be what I want, but it uses a #Configuration class instead of the XML configuration which I'm using and I don't want to move my entire spring xml definitions to a #Configuration class.
Can I define a customMethodCondition for RequestMappingHandlerMapping in the XML?
I tried subclassing RequestMappingHandlerMapping and override getCustomMethodCondition, to return my custom RequestCondition, but it didn't work - getMatchingCondition() in my condition didn't fire.
Any help would be greatly appreciated!
UPDATE
I read a little more, and it looks like RequestMappingHandlerMapping is a new class (since ver 3.1).
What happens in my app is that the #Configuration that tries to override and thereby redefine the requestMappingHandlerMapping bean actually works, but the url mappings (#RequestMapping methods in #Controllers) seem to get processed twice, once by the subclass ExtendedRequestMappingHandlerMapping and once by the original RequestMappingHandlerMapping --first with a custom condition, and then again without it.
Bottom line is my custom conditions are simply ignored.
This is supposed to be an advanced pattern, but IMO it should be quite common...
Comments anyone?
Spring MVC already provides a mechanism for distinguishing between json and html, the RequestMapping annotation takes a consumes attribute which looks at the content type of the request...
// REST version, Content-type is "application/json"
#RequestMapping(value = "/", consumes = "application/json")
public void myRestService() {
...
// HTML version, Content-type is not "application/json"
#RequestMapping(value = "/", consumes = "!application/json")
public void myHtmlService() {
...
Another way to use the same url but have distinct methods is with the param or headers attribute...
// the url is /?role=guest
#RequestMapping(value = "/", param = "role=guest")
public void guestService() {
// the url is / with header role=admin
#RequestMapping(value = "/", headers = "role=admin")
public void adminService() {
I would think you would want distinct urls for security. Typically, with something like Spring Security, you would put all of the admin functionality under /admin and let the framework manage it all...
<http auto-config="true">
<intercept-url pattern="/admin/**" access="ROLE_ADMIN" />
...
Would this be sufficient for your use case(s)?
If you have extended RequestMappingHandlerMapping(say ExtendedRequestMappingHandlerMapping) you have to register this new mapping a little differently in application context xml.
You cannot use <mvc:annotation-driven/> to configure the Spring MVC as that defines it's own handlerMapping internally, you can instead do something along these lines(or follow the approach in the link with #Configuration that you have provided):
<bean name="handlerAdapter" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="webBindingInitializer">
<bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<property name="conversionService" ref="conversionService"></property>
<property name="validator">
<bean class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
</property>
</bean>
</property>
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.ResourceHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
</list>
</property>
</bean>
<bean name="handlerMapping" class="..ExtendedRequestMappingHandlerMapping">
</bean>
This should ensure that your mapping takes effect and will ensure that the appropriate handler method is found by the handlerAdapter component.

Resources