Category: Blog

Get a Resource File’s Contents

No Comments Blog

Here is a little snippet on how to get the contents of a resource file.

String filePath = this.getClass().getClassLoader().getResource("folder/file.txt").getFile();
String fileContent = new String(Files.readAllBytes(Paths.get(filePath)), StandardCharsets.UTF_8);

And for reference here are the imports used
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;

A Simple CAS Java Rest Client Example

No Comments Blog

Here are some notes from creating a simple Java Client to access a REST endpoint behind CAS authentication.

Resourcs for enabling CAS Rest Access:

And here is my simple implementation:

  • Main.java contains a runnable main method and makes the calls to our REST service
  • CasLogin.java holds our user’s credentials and makes the call to get the TicketGrantingTicket and the ServiceGrantingTicket.  You might be able to store the TGT in order to avoid passing the credentials over the wire for each request.
  • RestClient.java holds some helper methods to make http calls

package com.bmchild.pocrestclient;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.logging.Logger;

import javax.security.sasl.AuthenticationException;

public class CasLogin {

private static final Logger LOGGER = Logger.getLogger(CasLogin.class.getName());

private String username;
private String password;
private String casUrl;
private RestClient restClient;

public CasLogin(String username, String password, String casUrl) {
this.username = username;
this.password = password;
this.casUrl = casUrl;
restClient = new RestClient();
}

public String getServiceTicket(String serviceUrl) throws IOException {
// get TGT
String location = getTicketGrantingTicket(username, password);

// get SGT
return getServiceGrantingTicket(location, serviceUrl);

}

/**
* With the TGT location and service url this will get the SGT
* @param tgtLocation
* @param serviceUrl
* @return
* @throws IOException
*/
private String getServiceGrantingTicket(String tgtLocation, String serviceUrl) throws IOException {
Map params = new LinkedHashMap<>();
params.put(“service”, serviceUrl);
params.put(“method”, “POST”);

HttpURLConnection conn = restClient.post(tgtLocation, params);
StringBuilder responseBuilder = new StringBuilder();
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream(), “UTF-8”));
String input;
while ((input = in.readLine()) != null) {
responseBuilder.append(input);
}
in.close();

String response = responseBuilder.toString();
LOGGER.info(“SGT -> ” + response);

return response;
}

/**
* Gets the TGT for the given username and password
* @param username
* @param password
* @return
* @throws IOException
*/
private String getTicketGrantingTicket(String username, String password) throws IOException {
Map params = new LinkedHashMap<>();
params.put(“username”, username);
params.put(“password”, password);
HttpURLConnection conn = restClient.post(casUrl, params);

if(conn.getResponseCode() == 400) {
throw new AuthenticationException(“bad username or password”);
}
String location = conn.getHeaderField(“Location”);
LOGGER.info(“TGT LOCATION -> ” + location);
return location;
}

}

package com.bmchild.pocrestclient;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

public class Main {

private static final Logger LOGGER = Logger.getLogger(Main.class.getName());
private static final String CAS_URL = “https://casserver.com/sso/v1/tickets”;
private static final String REST_BASE_URL = “http://restservice.com”;

public static void main(String[] args) throws IOException {

CasLogin casLogin = new CasLogin(“user”, “pass”, CAS_URL);
RestClient client = new RestClient();

/* example GET */
Main main = new Main();
String getSimple = REST_BASE_URL + “/rest/api/v1/messages”;
main.printContent( client.get(getSimple + “?ticket=” + casLogin.getServiceTicket(getSimple)) );

String getParams = REST_BASE_URL + “/rest/api/v1/messages?page=1”;
main.printContent( client.get(getParams + “&ticket=” + casLogin.getServiceTicket(getParams)));

String getSimple2 = REST_BASE_URL + “/rest/api/v1/messages/4405078”;
main.printContent( client.get(getSimple2 + “?ticket=” + casLogin.getServiceTicket(getSimple2)));

/* Example POST */
// see https://groups.google.com/forum/#!searchin/jasig-cas-user/post$20to$20rest$20resource/jasig-cas-user/NWmFahj9usk/YBECPJULN3sJ
// looks like should be false in our webapp’s spring security context (casContext.xml)
String postMessage = REST_BASE_URL + “/rest/api/v1/messages”;
Map params = new HashMap();
params.put(“body”, “message body”);
params.put(“toAddress”, “11220”); // from address lookup
params.put(“subject”, “message subject”);
main.printContent( client.post(postMessage + “?ticket=” + casLogin.getServiceTicket(postMessage), params));
}

private void printContent(HttpURLConnection con) {
if (con != null) {

try {

LOGGER.info(“Response Code -> ” + con.getResponseCode());
BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));

String input;
StringBuilder content = new StringBuilder();
while ((input = br.readLine()) != null) {
content.append(input);
}
br.close();
LOGGER.info(“Content -> ” + content.toString());

} catch (IOException e) {
e.printStackTrace();
}

}

}

}

package com.bmchild.pocrestclient;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Map;
import java.util.logging.Logger;

public class RestClient {

private static final Logger LOGGER = Logger.getLogger(RestClient.class.getName());

public URL createUrl(String url) throws MalformedURLException {
return new URL(url);
}

public HttpURLConnection get(String url) throws IOException {
LOGGER.info(“Getting from url ‘” + url +”‘”);

URL connectionUrl = createUrl(url);
return (HttpURLConnection) connectionUrl.openConnection();

}

/**
* Helper Method to post data to the given url and with the given params
* @param url
* @param params
* @return
* @throws IOException
*/
public HttpURLConnection post(String url, Map params) throws IOException {
LOGGER.info(“Posting to url ‘” + url +”‘ w/ params ‘” + params.toString() + “‘”);

URL connectionUrl = createUrl(url);
byte[] postDataBytes = convertParamMapToBytes(params);
HttpURLConnection conn = (HttpURLConnection)connectionUrl.openConnection();
conn.setRequestMethod(“POST”);
conn.setRequestProperty(“Content-Type”, “application/x-www-form-urlencoded”);
conn.setRequestProperty(“Content-Length”, String.valueOf(postDataBytes.length));
conn.setDoOutput(true);
conn.getOutputStream().write(postDataBytes);
return conn;
}

/**
* Helper method to convert a map to POST bytes
* @param params
* @return
* @throws UnsupportedEncodingException
*/
private byte[] convertParamMapToBytes(Map params) throws UnsupportedEncodingException {
StringBuilder postData = new StringBuilder();
for (Map.Entry param : params.entrySet()) {
if (postData.length() != 0) postData.append(‘&’);
postData.append(URLEncoder.encode(param.getKey(), “UTF-8”));
postData.append(‘=’);
postData.append(URLEncoder.encode(String.valueOf(param.getValue()), “UTF-8”));
}
return postData.toString().getBytes(“UTF-8”);
}

}

Creating a Culture of Learning and Innovation

No Comments Blog

This article is pretty cool. I found the benefits of learning described here to match my own experiences. Here’s my summary:

  • A Learning Culture is a prerequisite to being innovative
  • A Learning Culture increases employee morale
  • A Learning Culture can start with people teaching each other
  • A Learning Culture should keep up the momentum…don’t stop training

The Tragedy of Agile

No Comments Blog

I’ve recently become aware of some recent complaints about the agile methodology and as I’ve thought about these complaints it seems to me that the reason for these complaints is because people are too locked into doing what someone has ordered them to do to. What I mean by that is too often we’re not able to ask why we’re doing something other than the boss (or someone else like an expensive consultant) said so.

All too often agile, or any process decision, is directed from the top-down.  An executive/manager/lead gets wind of a way to make all their buggy, late, and expensive software problems go away.  All you have to do is follow a few simple rules.  Now the tragedy is the people who have to carry out these rules are never asked how they feel about these rules before they’re told to do them.  What we’re seeing is a bureaucratic, closed, and stale culture trying to implement a set of rules that are based on an open, transparent, and continuously improving culture.  The rules for the software development process just don’t seem to fit, but luckily nothing is set in stone.

This is your process…not Scrum’s

During my grad studies I took a class about lean manufacturing which is the basis for the Toyota Production System (TPS).  Basically, TPS is a culture, set of rules, guidelines, and processes that enable Toyota to eliminate waste in their business.   Eventually Toyota realized that it needed to help their suppliers eliminate waste so that they could work together better.  Our class took a tour of one of these suppliers called Autoliv.  Autoliv builds parts for Toyota’s airbags and with Toyota’s help they’ve been able to create a more efficient production system.  Now, do they call it the Toyota Production System?  No way.  Why?  Because they’re not Toyota, they’re Autoliv.  It’s the Autoliv Production System.  It was modeled after TPS but modified for their specific needs.
Don’t say we use the Scrum or OpenAgile or Waterfall or whatever methodology you’re basing your process off, because the truth of the matter is you aren’t.  You’re taking whatever you understand these methodologies to be and you’re applying it to your circumstances.  When you say you’re using Scrum it’s too easy to blame your problems on Scrum.  Take ownership of your development process because if there is a problem, you’ll need to fix it.  And by you I mean everyone on your team.

Empower the team.  They will come.

I’ve come to discover that self-organizing teams are incredibly productive and for the most part a lot happier than your traditional team (I wish I had empirical proof, but I don’t).  Part of the self-organizing team is shared responsibility.  You fail together and you succeed together.  Most people I’ve come across(sure there’s a few dicks out there) are going to want the team to succeed and will share ideas on how to improve. Whether code or development process, the team needs to be able to adjust to better increase their chances of success.  In order to do that they need to be able to experiment with their ideas without going through miles of red tape.  Does experimentation lead to some failures?  Absolutely, but it is the only way to improve.
Another important aspect of the team is having clear roles.  Generally, you’ll have your product owner and your customers and your project manager (some people might call this scrum master for some weird reason), and your developers.  Your process might have more and maybe less (do you see a problem with having less?), but the fact of the matter is if you know who has what role, and what specific duties are included in that role, there won’t be as many conflicts of people trying to do the same thing.  For example, if you have a clear product owner who is driving the direction of the project you won’t be receiving conflicting feature requests.  Again, it’s important to understand why you have each role on the team.  If you don’t know why, you probably don’t need it and you can move that person to QA since they’re probably overloaded anyways.

Tool not rules

As I’ve come to better understand agile, lean, theory of constraints, and other ideas of improving processes the better I’ve come to understand that all the ideas and strategies are simply tools.  Tools that I can choose to use in a certain situation where necessary or, if it wouldn’t be effective, to leave in the toolbox.  You wouldn’t use a sledge hammer to hang a picture would you?
In carpentry it’s generally pretty easy to decide on which tool for a job, but it may not be so easy for software development.  For this reason it’s important that you’re measuring the right things to see if a tool really is beneficial.  I agree that this is way easier said than done, but at the very least you should know how long, on average, a feature takes to go from inception to release.  That way you can monitor any changes that come about from your experimentation(remember the scientific method?).
Some other useful metrics might be ROI, velocity and there are a slew of others.  And once again, understand why you’re measuring something, because truth be told, measuring can be a pain.

So…

If I were to have you remember anything from this article, understand why you’re doing what you’re doing. I sincerely hope that you’re in an organization where that’s okay.  If not you might have a hard time trying to convince people to change, but I’ve found that most people are willing to change If they understand why it would be better.
And if you were to remember some other things it would be good to also remember that it’s YOUR software development process, for better or for worse.  The sooner you realize that the better for you and your team. And lastly, use tools that are good for the job.
So, by following these few simple rules (maybe I’ll name it the Be Awesome To Each Other Methodology), you too can enjoy your job in software development.
Seriously though,  I am interested in your stories, ideas, anecdotes, etc.

Creating a Custom Regex Spring Security 3.1 Expression

No Comments Blog

Summary: What classes to extend in order to make a custom spEL expression for validating with Spring Security 3.1

The other day I found that I would like a way to authorize a user based on a wild card or, better yet, a regex expression, something like:

@PreAuthorize(“hasRegexRole(‘.*_ADMIN’)”)

After much looking around I came up with the following.

First we tell Spring to look at our expression handler for method and web authorization.

    <!--
        Enable class- and method-level security via annotations
    -->
    <sec:global-method-security pre-post-annotations="enabled" secured-annotations="enabled">
    	 <sec:expression-handler ref="expressionHandler"/>
    </sec:global-method-security>

    <!--
        WebSecurityExpressHandler for Spring Security JSP tags
    -->
    <bean id="webSecurityExpressionHandler" class="com.bmchild.security.access.expression.CustomWebSecurityExpressionHandler"/>
    
    <!-- Custom Expression Handler -->
    <bean id="expressionHandler" class="com.bmchild.security.access.expression.CustomMethodSecurityExpressionHandler" />

package com.bmchild.security.access.expression;

import org.aopalliance.intercept.MethodInvocation;
import org.apache.log4j.Logger;
import org.springframework.security.access.expression.SecurityExpressionRoot;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.core.Authentication;

/**
* @author bchild
*
*/
public class CustomMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler {

Logger LOGGER = Logger.getLogger(CustomMethodSecurityExpressionHandler.class);

public CustomMethodSecurityExpressionHandler() {
super();
}

/* (non-Javadoc)
* @see org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler#createSecurityExpressionRoot(org.springframework.security.core.Authentication, org.aopalliance.intercept.MethodInvocation)
*/
@Override
protected SecurityExpressionRoot createSecurityExpressionRoot(Authentication authentication, MethodInvocation invocation) {
CustomSecurityExpressionRoot root = new CustomSecurityExpressionRoot(authentication);
root.setPermissionEvaluator(getPermissionEvaluator());

return root;
}

}

And we define our custom security root with our new expression method. Also note the hasIpAddress method. This is there to replace the WebSecurityExpressionRoot so that we can use our new expression on JSPs with spring security’s tag.

package com.bmchild.security.access.expression;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;
import org.springframework.security.access.expression.SecurityExpressionRoot;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.util.IpAddressMatcher;

/**
*
* Security Expression evaluator for wildcard use
*
* @author bchild
*
*/
public class CustomSecurityExpressionRoot extends SecurityExpressionRoot {

Logger LOGGER = Logger.getLogger(CustomSecurityExpressionRoot.class);

private Set userRoles;
/*
* This is for emulating WebSecurityExpressionRoot
*/
public HttpServletRequest request;

/**
* @param a
*/
public CustomSecurityExpressionRoot(Authentication a) {
super(a);
}

public CustomSecurityExpressionRoot(Authentication a, FilterInvocation fi) {
super(a);
this.request = fi.getRequest();
}

/**
* Checks given roles against the given regex expression
*
* @param regex
* to match agains roles
* @return true if at least 1 authority matches the regex, otherwise false
*/
public boolean hasRegexRole(String regex) {

if (LOGGER.isDebugEnabled()) {
LOGGER.debug(“hasRegexRole: ” + regex);
}

boolean found = false;

Set authorities = getCustomAuthoritySet();

for (String authority : authorities) {

if (authority.matches(regex)) {
found = true;
break;
}

}

if (LOGGER.isDebugEnabled()) {
LOGGER.debug(“hasRegexRole returns ” + found);
}

return found;
}

/**
*
* @see org.springframework.security.web.access.expression.
* WebSecurityExpressionRoot.hasIpAddress(String) Takes a specific IP
* address or a range using the IP/Netmask (e.g. 192.168.1.0/24 or
* 202.24.0.0/14).
*
* @param ipAddress
* the address or range of addresses from which the request must
* come.
* @return true if the IP address of the current request is in the required
* range.
*/
public boolean hasIpAddress(String ipAddress) {
return (new IpAddressMatcher(ipAddress).matches(request));
}

/**
* Note: this does not return hierchacal roles like
* org.springframework.security
* .access.expression.SecurityExpressionRoot.getAuthoritySet()
*
* @return set of authorities
*/
private Set getCustomAuthoritySet() {

if (userRoles == null) {
userRoles = new HashSet();
Collection userAuthorities = authentication.getAuthorities();

userRoles = AuthorityUtils.authorityListToSet(userAuthorities);
}

return userRoles;
}

}

Test!

package com.bmchild.security.access.expression;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.util.ArrayList;
import java.util.Collection;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;

/**
* @author bchild
*
*/
@RunWith(MockitoJUnitRunner.class)
public class CustomSecurityExpressionRootTest {

private CustomSecurityExpressionRoot expression;

private Authentication auth;

@Before
public void before() {
auth = mock(Authentication.class);
expression = new CustomSecurityExpressionRoot(auth);
}

/**
* Test method for {@link com.crengland.security.access.expression.CustomSecurityExpressionRoot#hasRegexRole(java.lang.String)}.
*/
@Test
public void testHasRegexRole() {

// Mock
final Collection authorities = new ArrayList();
authorities.add( new SimpleGrantedAuthority(“ROLE_1_ADMIN”) );
authorities.add( new SimpleGrantedAuthority(“ROLE_2_ADMIN”) );
authorities.add( new SimpleGrantedAuthority(“ROLE_3_ADMIN”) );
authorities.add( new SimpleGrantedAuthority(“ROLE_1_NONADMIN”) );

when(auth.getAuthorities()).thenAnswer( new Answer>() {

@Override
public Collection answer(InvocationOnMock invocation) throws Throwable {
return authorities;
}
});

// Test
assertTrue( expression.hasRegexRole(“ROLE_1_ADMIN”) );
assertTrue( expression.hasRegexRole(“ROLE_.+_ADMIN”) );
assertFalse( expression.hasRegexRole(“ROLE__ADMIN”) );
assertTrue( expression.hasRegexRole(“ROLE_[\\d]+_NONADMIN”) );

// Verify
verify(auth).getAuthorities();

}

}

And we create a custom web security expression handler that returns our custom security root. Again this allows us to use our custom expression method in JSPs, or in URLs if you really wanted.

package com.bmchild.security.access.expression;

import org.springframework.security.access.expression.SecurityExpressionRoot;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;

/**
* @author bchild
*
*/
public class CustomWebSecurityExpressionHandler extends DefaultWebSecurityExpressionHandler {

@Override
protected SecurityExpressionRoot createSecurityExpressionRoot(Authentication authentication, FilterInvocation fi) {
CustomSecurityExpressionRoot root = new CustomSecurityExpressionRoot(authentication, fi);
root.setPermissionEvaluator(getPermissionEvaluator());
return root;
}
}