Skip to content

Instantly share code, notes, and snippets.

@dsyer
Created April 19, 2012 14:06
Show Gist options
  • Save dsyer/2421187 to your computer and use it in GitHub Desktop.
Save dsyer/2421187 to your computer and use it in GitHub Desktop.
Spring Security OAuth2 samples with custom OAuth2 endpoint URLs
*/src/META-INF/
*/src/main/java/META-INF/
samples/*/*/src/main/webapp/META-INF/
target/
.classpath
.project
.DS_Store
.settings/
*.iml
*.iws
*.ipr
.idea/
cargo-installs/
atlassian-ide-plugin.xml
<?xml version="1.0" encoding="UTF-8"?>
<beansProjectDescription>
<version>1</version>
<pluginVersion><![CDATA[2.6.0.201104111100-PATCH]]></pluginVersion>
<configSuffixes>
<configSuffix><![CDATA[xml]]></configSuffix>
</configSuffixes>
<enableImports><![CDATA[false]]></enableImports>
<configs>
<config>src/main/webapp/WEB-INF/spring-servlet.xml</config>
</configs>
<configSets>
</configSets>
</beansProjectDescription>
<?xml version="1.0" encoding="UTF-8"?>
<beansProjectDescription>
<version>1</version>
<pluginVersion><![CDATA[2.6.0.201104111100-PATCH]]></pluginVersion>
<configSuffixes>
<configSuffix><![CDATA[xml]]></configSuffix>
</configSuffixes>
<enableImports><![CDATA[false]]></enableImports>
<configs>
<config>src/main/webapp/WEB-INF/spring-servlet.xml</config>
</configs>
<configSets>
</configSets>
</beansProjectDescription>

Spring Security OAuth2 samples with custom OAuth2 endpoint URLs

<%@ page import="org.springframework.security.core.AuthenticationException" %>
<%@ page import="org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter" %>
<%@ page import="org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException" %>
<%@ taglib prefix="authz" uri="http://www.springframework.org/security/tags" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"/>
<title>Sparklr</title>
<link type="text/css" rel="stylesheet" href="<c:url value="/style.css"/>"/>
</head>
<body>
<h1>Sparklr</h1>
<div id="content">
<% if (session.getAttribute(AbstractAuthenticationProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY) != null && !(session.getAttribute(AbstractAuthenticationProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY) instanceof UnapprovedClientAuthenticationException)) { %>
<div class="error">
<h2>Woops!</h2>
<p>Access could not be granted. (<%= ((AuthenticationException) session.getAttribute(AbstractAuthenticationProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY)).getMessage() %>)</p>
</div>
<% } %>
<c:remove scope="session" var="SPRING_SECURITY_LAST_EXCEPTION"/>
<authz:authorize ifAllGranted="ROLE_USER">
<h2>Please Confirm</h2>
<p>You hereby authorize "<c:out value="${client.clientId}"/>" to access your protected resources.</p>
<form id="confirmationForm" name="confirmationForm" action="<%=request.getContextPath()%>/authorize" method="post">
<input name="user_oauth_approval" value="true" type="hidden"/>
<label><input name="authorize" value="Authorize" type="submit"></label>
</form>
<form id="denialForm" name="denialForm" action="<%=request.getContextPath()%>/authorize" method="post">
<input name="user_oauth_approval" value="false" type="hidden"/>
<label><input name="deny" value="Deny" type="submit"></label>
</form>
</authz:authorize>
</div>
<div id="footer">Sample application for <a href="http://github.com/SpringSource/spring-security-oauth" target="_blank">Spring Security OAuth</a></div>
</body>
</html>
package org.springframework.security.oauth.examples.sparklr.mvc;
import java.util.TreeMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.provider.AuthorizationRequest;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.ModelAndView;
/**
* Controller for retrieving the model for and displaying the confirmation page
* for access to a protected resource.
*
* @author Ryan Heaton
*/
@Controller
@SessionAttributes(types = AuthorizationRequest.class)
public class AccessConfirmationController {
private ClientDetailsService clientDetailsService;
@RequestMapping("/oauth/confirm_access")
public ModelAndView getAccessConfirmation(@ModelAttribute AuthorizationRequest clientAuth) throws Exception {
ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId());
TreeMap<String, Object> model = new TreeMap<String, Object>();
model.put("auth_request", clientAuth);
model.put("client", client);
return new ModelAndView("access_confirmation", model);
}
@Autowired
public void setClientDetailsService(ClientDetailsService clientDetailsService) {
this.clientDetailsService = clientDetailsService;
}
}
package org.springframework.security.oauth.examples.sparklr.mvc;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.oauth.examples.sparklr.oauth.SparklrUserApprovalHandler;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.ConsumerTokenServices;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
/**
* Controller for resetting the token store for testing purposes.
*
* @author Dave Syer
*/
@Controller
public class AdminController {
private ConsumerTokenServices tokenServices;
private SparklrUserApprovalHandler userApprovalHandler;
@RequestMapping("/oauth/cache_approvals")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void startCaching() throws Exception {
userApprovalHandler.setUseTokenServices(true);
}
@RequestMapping("/oauth/uncache_approvals")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void stopCaching() throws Exception {
userApprovalHandler.setUseTokenServices(false);
}
@RequestMapping("/oauth/users/{user}/tokens")
@ResponseBody
public Collection<OAuth2AccessToken> listTokensForUser(@PathVariable String user, Principal principal)
throws Exception {
checkResourceOwner(user, principal);
return enhance(tokenServices.findTokensByUserName(user));
}
@RequestMapping(value = "/oauth/users/{user}/tokens/{token}", method = RequestMethod.DELETE)
public ResponseEntity<Void> revokeToken(@PathVariable String user, @PathVariable String token, Principal principal)
throws Exception {
checkResourceOwner(user, principal);
if (tokenServices.revokeToken(token)) {
return new ResponseEntity<Void>(HttpStatus.NO_CONTENT);
} else {
return new ResponseEntity<Void>(HttpStatus.NOT_FOUND);
}
}
@RequestMapping("/oauth/clients/{client}/tokens")
@ResponseBody
public Collection<OAuth2AccessToken> listTokensForClient(@PathVariable String client) throws Exception {
return enhance(tokenServices.findTokensByClientId(client));
}
private Collection<OAuth2AccessToken> enhance(Collection<OAuth2AccessToken> tokens) {
Collection<OAuth2AccessToken> result = new ArrayList<OAuth2AccessToken>();
for (OAuth2AccessToken prototype : tokens) {
DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(prototype);
String clientId = tokenServices.getClientId(token.getValue());
if (clientId != null) {
Map<String, Object> map = new HashMap<String, Object>(token.getAdditionalInformation());
map.put("client_id", clientId);
token.setAdditionalInformation(map);
result.add(token);
}
}
return result;
}
private void checkResourceOwner(String user, Principal principal) {
if (principal instanceof OAuth2Authentication) {
OAuth2Authentication authentication = (OAuth2Authentication) principal;
if (!authentication.isClientOnly() && !user.equals(principal.getName())) {
throw new AccessDeniedException(String.format("User '%s' cannot obtain tokens for user '%s'",
principal.getName(), user));
}
}
}
/**
* @param userApprovalHandler the userApprovalHandler to set
*/
public void setUserApprovalHandler(SparklrUserApprovalHandler userApprovalHandler) {
this.userApprovalHandler = userApprovalHandler;
}
/**
* @param tokenServices the consumerTokenServices to set
*/
public void setTokenServices(ConsumerTokenServices tokenServices) {
this.tokenServices = tokenServices;
}
}
<!--
This file contains useful Ant definitions for users of App Engine.
To use these macrodefs and taskdefs, import the file into your own build.xml:
<property name="appengine.sdk.dir" location="/some_dir/appengine-java-sdk-trunk"/>
<import file="${appengine.sdk.dir}/config/user/ant-macros.xml"/>
For example uses of the macros, see the template project's build.xml.
-->
<project name="appengine-ant-macros">
<property name="appengine.sdk.home" location="${sdk.dir}"/>
<property name="appengine.tools.classpath"
location="${appengine.sdk.home}/lib/appengine-tools-api.jar"/>
<!--
A macrodef for dev_appserver. Use like:
<dev_appserver war="${war}"/>
-->
<macrodef name="dev_appserver" description="Runs the App Engine Development App Server">
<attribute name="war" description="The exploded war directory containing the application"/>
<attribute name="port" default="8080" description="The port the server starts on"/>
<attribute name="address" default="localhost" description="The interface the server binds to"/>
<element name="options" optional="true" description="Additional options for dev_appserver"/>
<element name="args" optional="true" description="Additional arguments for the java task"/>
<sequential>
<java classname="com.google.appengine.tools.KickStart"
classpath="${appengine.tools.classpath}"
fork="true">
<arg value="com.google.appengine.tools.development.DevAppServerMain"/>
<arg value="--port=@{port}"/>
<arg value="--address=@{address}"/>
<options/>
<arg value="@{war}"/>
<args/>
</java>
</sequential>
</macrodef>
<!--
A macrodef for appcfg. Use like:
<appcfg action="update" war="${war}"/>
-->
<macrodef name="appcfg" description="Manages an application">
<attribute name="war" description="The exploded war directory containing the application"/>
<attribute name="action" description="One of (update, rollback, update_indexes, request_logs)"/>
<element name="options" optional="true" description="Options for appcfg (such as --server, --num_days, etc...)"/>
<element name="args" optional="true" description="Additional arguments for the java task"/>
<sequential>
<java classname="com.google.appengine.tools.admin.AppCfg"
classpath="${appengine.tools.classpath}"
fork="true">
<arg value="--disable_prompt"/>
<options/>
<arg value="@{action}"/>
<arg value="@{war}"/>
<args/>
</java>
</sequential>
</macrodef>
<!--
A taskdef for ORM enhancement. Use like:
<enhance failonerror="true">
<classpath>
<pathelement path="${appengine.tools.classpath}"/>
<pathelement path="@{war}/WEB-INF/classes"/>
<fileset dir="@{war}/WEB-INF/lib" includes="*.jar"/>
</classpath>
<fileset dir="@{war}/WEB-INF/classes" includes="**/*.class"/>
</enhance>
Alternatively, use the <enhance_war/> macrodef below.
-->
<taskdef name="enhance"
classpath="${appengine.tools.classpath}"
classname="com.google.appengine.tools.enhancer.EnhancerTask"/>
<!--
A macrodef for ORM enhancement for a war. Use like:
<enhance_war war="${war}"/>
-->
<macrodef name="enhance_war" description="Run the ORM enhancer on an exploded war">
<attribute name="war" description="The exploded war directory containing the application"/>
<element name="args" optional="true" description="Additional arguments to the enhancer"/>
<sequential>
<enhance failonerror="true">
<args/>
<classpath>
<pathelement path="${appengine.tools.classpath}"/>
<pathelement path="@{war}/WEB-INF/classes"/>
<fileset dir="@{war}/WEB-INF/lib" includes="*.jar"/>
</classpath>
<fileset dir="@{war}/WEB-INF/classes" includes="**/*.class"/>
</enhance>
</sequential>
</macrodef>
</project>
<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<application>${gae.application.name}</application>
<version>1</version>
<sessions-enabled>true</sessions-enabled>
</appengine-web-app>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Client Authentication Example</title>
<link type="text/css" rel="stylesheet" href="style.css" />
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script>
function authenticate() {
var appID = "my-less-trusted-client";
var path = 'oauth/authorize?';
var queryParams = [ 'client_id=' + appID,
'redirect_uri=' + window.location, 'scope=trust',
'response_type=token' ];
var query = queryParams.join('&');
var url = path + query;
window.open(url);
}
function display() {
var hash = window.location.hash;
var accessToken = hash.split('&')[0].split("=")[1];
console.log('access-token:' + accessToken);
var headers = {
'Authorization' : 'Bearer ' + accessToken,
'Accept' : 'application/json'
};
$.ajaxSetup({
'headers' : headers,
dataType : 'text'
});
$.get('photos/user/message', function(data) {
console.log('data:' + data);
$('#message').text(data);
});
}
$(function() {
if (window.location.hash.length == 0) {
authenticate();
} else {
display();
}
})
</script>
</head>
<body>
<h1>Sparklr Client Authentication Sample</h1>
<div id="content">
<p>Once you have authenticated and approved the access, some
JavaScript in this page will render a message from Sparklr below</p>
<p id="message" />
</div>
</body>
</html>
<project name="sparklr2">
<fail unless="gae.sdk" message="You must specify a 'gae.sdk' property."/>
<property name="sdk.dir" location="${gae.sdk}"/>
<import file="ant-macros.xml"/>
<property name="war.dir" value="target/sparklr2-2.0-SNAPSHOT"/>
<target name="runserver" description="Starts the development server.">
<dev_appserver war="${war.dir}" port="8080"/>
</target>
<target name="update" description="Uploads the application to App Engine.">
<appcfg action="update" war="${war.dir}"/>
</target>
<target name="update_indexes" description="Uploads just the datastore index configuration to App Engine.">
<appcfg action="update_indexes" war="${war.dir}"/>
</target>
<target name="rollback" description="Rolls back an interrupted application update.">
<appcfg action="rollback" war="${war.dir}"/>
</target>
<target name="request_logs" description="Downloads log data from App Engine for the application.">
<appcfg action="request_logs" war="${war.dir}">
<options>
<arg value="--num_days=5"/>
</options>
<args>
<arg value="logs.txt"/>
</args>
</appcfg>
</target>
</project>
org.apache.commons.logging.LogFactory=org.apache.commons.logging.impl.LogFactoryImpl
org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog
org.apache.commons.logging.LogFactory=org.apache.commons.logging.impl.LogFactoryImpl
org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8">
<link href="main.css" rel="stylesheet" type="text/css"/>
<title>Tonr JS Client Demo</title>
<script src="js/libs/json2.js"></script>
<script src="js/libs/localstorage.js"></script>
<script src="js/libs/modernizr-2.5.3.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="js/libs/jso.js"></script>
<script type="text/javascript">
$(document).ready(function() {
// Add configuration for one or more providers.
jso_configure({
"sparklr": {
client_id: "tonr",
redirect_uri: "http://localhost:8080/tonr2/demo.html",
authorization: "http://localhost:8080/sparklr2/oauth/authorize",
}
});
// Perform a data request
$.oajax({
url: "http://localhost:8080/sparklr2/photos?format=json",
jso_provider: "sparklr", // Will match the config identifier
jso_scopes: ["read"], // List of scopes (OPTIONAL)
jso_allowia: true, // Allow user interaction (OPTIONAL, default: false)
dataType: 'json',
success: function(data) {
console.log({response:data});
$('#message').text(JSON.stringify(data));
}
});
jso_wipe();
});
</script>
</head>
<body>
<h1>Sparklr Client Authentication Sample</h1>
<div id="content">
<p>Once you have authenticated and approved the access, some
JavaScript in this page will render a list of photos from Sparklr below:</p>
<p id="message" />
</div>
</body>
</html>
<%@ taglib prefix="authz" uri="http://www.springframework.org/security/tags" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link href="<c:url value="/main.css"/>" rel="stylesheet" type="text/css"/>
<title>tonr</title>
</head>
<body>
<div id="container">
<ul id="mainlinks">
<li><a href="<c:url value="/index.jsp"/>">home</a></li>
<authz:authorize ifNotGranted="ROLE_USER">
<li><a href="<c:url value="/login.jsp"/>">login</a></li>
</authz:authorize>
<li><a href="<c:url value="/sparklr/photos"/>">sparklr pics</a></li>
<li><a href="<c:url value="/facebook/info"/>" class="selected">facebook friends</a></li>
</ul>
<div id="content">
<h1>Your Facebook Friends:</h1>
<ul>
<c:forEach var="friendName" items="${friends}">
<li><c:out value="${friendName}"/></li>
</c:forEach>
</ul>
</div>
</div>
</body>
</html>
package org.springframework.security.oauth.examples.tonr.mvc;
import java.util.ArrayList;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.node.ArrayNode;
import org.codehaus.jackson.node.ObjectNode;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.client.RestOperations;
/**
* @author Ryan Heaton
* @author Dave Syer
*/
@Controller
public class FacebookController {
private RestOperations facebookRestTemplate;
@RequestMapping("/facebook/info")
public String photos(Model model) throws Exception {
ObjectNode result = facebookRestTemplate
.getForObject("https://graph.facebook.com/me/friends", ObjectNode.class);
ArrayNode data = (ArrayNode) result.get("data");
ArrayList<String> friends = new ArrayList<String>();
for (JsonNode dataNode : data) {
friends.add(dataNode.get("name").getTextValue());
}
model.addAttribute("friends", friends);
return "facebook";
}
public void setFacebookRestTemplate(OAuth2RestTemplate facebookRestTemplate) {
this.facebookRestTemplate = facebookRestTemplate;
}
}
<%@ taglib prefix="authz" uri="http://www.springframework.org/security/tags" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"/>
<title>Sparklr</title>
<link type="text/css" rel="stylesheet" href="<c:url value="/style.css"/>"/>
<authz:authorize ifAllGranted="ROLE_USER">
<script type='text/javascript'>
function pictureDisplay(json) {
for (var i = 0; i < json.photos.length; i++) {
var photo = json.photos[i];
document.write('<img src="photos/' + photo.id + '" alt="' + photo.name + '">');
}
}
</script>
</authz:authorize>
</head>
<body>
<h1>Sparklr</h1>
<div id="content">
<h2>Home</h2>
<p>This is a great site to store and view your photos. Unfortunately, we don't have any services
for printing your photos. For that, you'll have to go to Tonr.</p>
<authz:authorize ifNotGranted="ROLE_USER">
<h2>Login</h2>
<form id="loginForm" name="loginForm" action="<c:url value="/login.do"/>" method="post">
<p><label>Username: <input type='text' name='j_username' value="marissa"></label></p>
<p><label>Password: <input type='text' name='j_password' value="koala"></label></p>
<p><input name="login" value="Login" type="submit"></p>
</form>
</authz:authorize>
<authz:authorize ifAllGranted="ROLE_USER">
<div style="text-align: center"><form action="<c:url value="/logout.do"/>"><input type="submit" value="Logout"></form></div>
<h2>Your Photos</h2>
<p>
<script type='text/javascript' src='photos?callback=pictureDisplay&format=json'></script>
</p>
</authz:authorize>
</div>
<div id="footer">Sample application for <a href="http://github.com/SpringSource/spring-security-oauth" target="_blank">Spring Security OAuth</a></div>
</body>
</html>
<%@ taglib prefix="authz" uri="http://www.springframework.org/security/tags" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link href="<c:url value="/main.css"/>" rel="stylesheet" type="text/css"/>
<title>tonr</title>
</head>
<body>
<div id="container">
<ul id="mainlinks">
<li><a href="<c:url value="/index.jsp"/>" class="selected">home</a></li>
<authz:authorize ifNotGranted="ROLE_USER">
<li><a href="<c:url value="/login.jsp"/>">login</a></li>
</authz:authorize>
<li><a href="<c:url value="/sparklr/photos"/>">sparklr pics</a></li>
<li><a href="<c:url value="/facebook/info"/>">facebook friends</a></li>
</ul>
<div id="content">
<h1>Welcome to Tonr.com!</h1>
<p>This is a website that will allow you to print your photos that you've uploaded to <a href="http://localhost:8080/sparklr/">sparklr.com</a>!
And since this site uses <a href="http://oauth.net">OAuth</a> to access your photos, we will never ask you
for your Sparklr credentials.</p>
<p>Tonr.com has only two users: "marissa" and "sam". The password for "marissa" is password is "wombat" and for "sam" is password is "kangaroo".</p>
<authz:authorize ifNotGranted="ROLE_USER">
<p><a href="<c:url value="login.jsp"/>">Login to Tonr</a></p>
</authz:authorize>
<authz:authorize ifAllGranted="ROLE_USER">
<p><a href="<c:url value="/sparklr/photos"/>">View my Sparklr photos</a></p>
</authz:authorize>
<p class="footer">Courtesy <a href="http://www.openwebdesign.org">Open Web Design</a> Thanks to <a href="http://www.dubaiapartments.biz/">Dubai Hotels</a></p>
</div>
</div>
</body>
</html>
(function(exp, $) {
var
config = {},
default_lifetime = 3600;
/*
* ------ SECTION: Utilities
*/
/*
* Returns a random string used for state
*/
var uuid = function() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
return v.toString(16);
});
}
/*
* Takes an URL as input and a params object.
* Each property in the params is added to the url as query string parameters
*/
var encodeURL= function(url, params) {
var res = url;
var k, i = 0;
for(k in params) {
res += (i++ === 0 ? '?' : '&') + encodeURIComponent(k) + '=' + encodeURIComponent(params[k]);
}
return res;
}
/*
* Returns epoch, seconds since 1970.
* Used for calculation of expire times.
*/
var epoch = function() {
return Math.round(new Date().getTime()/1000.0);
}
/*
* Redirects the user to a specific URL
*/
var redirect = function(url) {
window.location = url;
// $("body").append('<p><a href="' + url + '">Go here...</a></p>');
}
var parseQueryString = function (qs) {
var e,
a = /\+/g, // Regex for replacing addition symbol with a space
r = /([^&;=]+)=?([^&;]*)/g,
d = function (s) { return decodeURIComponent(s.replace(a, " ")); },
q = qs,
urlParams = {};
while (e = r.exec(q))
urlParams[d(e[1])] = d(e[2]);
return urlParams;
}
/*
* ------ / SECTION: Utilities
*/
/*
* ------ SECTION: Storage for Tokens and state
*/
/*
saveState stores an object with an Identifier.
TODO: Ensure that both localstorage and JSON encoding has fallbacks for ancient browsers.
In the state object, we put the request object, plus these parameters:
* restoreHash
* providerID
* scopes
*/
var saveState = function(state, obj) {
// console.log("SaveState (" + state+ ")");
localStorage.setItem("state-" + state, JSON.stringify(obj));
};
/*
* getState returns the state object, but also removes it.
*/
var getState = function(state) {
// console.log("getState (" + state+ ")");
var obj = JSON.parse(localStorage.getItem("state-" + state));
localStorage.removeItem("state-" + state)
return obj;
};
/*
* Checks if a token, has includes a specific scope.
* If token has no scope at all, false is returned.
*/
var hasScope = function(token, scope) {
var i;
if (!token.scopes) return false;
for(i = 0; i < token.scopes.length; i++) {
if (token.scopes[i] === scope) return true;
}
return false;
};
/*
* Takes an array of tokens, and removes the ones that
* are expired, and the ones that do not meet a scopes requirement.
*/
var filterTokens = function(tokens, scopes) {
var i, j,
result = [],
now = epoch(),
usethis;
if (!scopes) scopes = [];
for(i = 0; i < tokens.length; i++) {
usethis = true;
// Filter out expired tokens. Tokens that is expired in 1 second from now.
if (tokens[i].expires && tokens[i].expires < (now+1)) usethis = false;
// Filter out this token if not all scope requirements are met
for(j = 0; j < scopes.length; j++) {
if (!hasScope(tokens[i], scopes[j])) usethis = false;
}
if (usethis) result.push(tokens[i]);
}
return result;
};
/*
* saveTokens() stores a list of tokens for a provider.
Usually the tokens stored are a plain Access token plus:
* expires : time that the token expires
* providerID: the provider of the access token?
* scopes: an array with the scopes (not string)
*/
var saveTokens = function(provider, tokens) {
// console.log("Save Tokens (" + provider+ ")");
localStorage.setItem("tokens-" + provider, JSON.stringify(tokens));
};
var getTokens = function(provider) {
// console.log("Get Tokens (" + provider+ ")");
var tokens = JSON.parse(localStorage.getItem("tokens-" + provider));
if (!tokens) tokens = [];
// console.log(tokens)
return tokens;
};
var wipeTokens = function(provider) {
localStorage.removeItem("tokens-" + provider);
};
/*
* Save a single token for a provider.
* This also cleans up expired tokens for the same provider.
*/
var saveToken = function(provider, token) {
var tokens = getTokens(provider);
tokens = filterTokens(tokens);
tokens.push(token);
saveTokens(provider, tokens);
};
/*
* Get a token if exists for a provider with a set of scopes.
* The scopes parameter is OPTIONAL.
*/
var getToken = function(provider, scopes) {
var tokens = getTokens(provider);
tokens = filterTokens(tokens, scopes);
if (tokens.length < 1) return null;
return tokens[0];
};
/*
* ------ /SECTION: Storage for Tokens and state
*/
/**
* Check if the hash contains an access token.
* And if it do, extract the state, compare with
* config, and store the access token for later use.
*/
var jso_checkfortoken = function() {
var
atoken,
h = window.location.hash,
now = epoch(),
state,
co;
/*
* Start with checking if there is a token in the hash
*/
if (h.length < 2) return;
if (h.indexOf("access_token") === -1) return;
h = h.substring(1);
var atoken = parseQueryString(h);
if (!atoken.state) return;
state = getState(atoken.state);
if (!state) throw "Could not retrieve state";
if (!state.providerID) throw "Could not get providerid from state";
if (!config[state.providerID]) throw "Could not retrieve config for this provider.";
co = config[state.providerID];
/*
* Decide when this token should expire.
* Priority fallback:
* 1. Access token expires_in
* 2. Life time in config (may be false = permanent...)
* 3. Specific permanent scope.
* 4. Default library lifetime:
*/
if (atoken["expires_in"]) {
atoken["expires"] = now + atoken["expires_in"];
} else if (co["default_lifetime"] === false) {
// Token is permanent.
} else if (co["default_lifetime"]) {
atoken["expires"] = now + co["default_lifetime"];
} else if (co["permanent_scope"]) {
if (!hasScope(atoken, co["permanent_scope"])) {
atoken["expires"] = now + default_lifetime;
}
} else {
atoken["expires"] = now + default_lifetime;
}
/*
* Handle scopes for this token
*/
if (atoken["scope"]) {
atoken["scopes"] = atoken["scope"].split(" ");
} else if (state["scopes"]) {
atoken["scopes"] = state["scopes"];
}
saveToken(state.providerID, atoken);
if (state.restoreHash) {
window.location.hash = state.restoreHash;
} else {
window.location.hash = '';
}
// console.log(atoken);
}
/*
* A config object contains:
*/
var jso_authrequest = function(providerid, scopes) {
var
state,
request,
authurl,
co;
if (!config[providerid]) throw "Could not find configuration for provider " + providerid;
co = config[providerid];
// console.log("About to send an authorization request to [" + providerid + "]. Config:")
// console.log(co);
state = uuid();
request = {
"response_type": "token"
};
request.state = state;
if (co["redirect_uri"]) {
request["redirect_uri"] = co["redirect_uri"];
}
if (co["client_id"]) {
request["client_id"] = co["client_id"];
}
if (scopes) {
request["scope"] = scopes.join(" ");
}
authurl = encodeURL(co.authorization, request);
// We'd like to cache the hash for not loosing Application state.
// With the implciit grant flow, the hash will be replaced with the access
// token when we return after authorization.
if (window.location.hash) {
request["restoreHash"] = window.location.hash;
}
request["providerID"] = providerid;
if (scopes) {
request["scopes"] = scopes;
}
// console.log("Saving state [" + state+ "]");
// console.log(JSON.parse(JSON.stringify(request)));
saveState(state, request);
redirect(authurl);
};
exp.jso_ensureTokens = function (ensure) {
var providerid, scopes, token;
for(providerid in ensure) {
scopes = undefined;
if (ensure[providerid]) scopes = ensure[providerid];
token = getToken(providerid, scopes);
// console.log("Ensure token for provider [" + providerid + "] ");
// console.log(token);
if (token === null) {
jso_authrequest(providerid, scopes);
}
}
return true;
}
exp.jso_configure = function(c) {
config = c;
try {
jso_checkfortoken();
} catch(e) {
console.log("Error when retrieving token from hash: " + e);
window.location.hash = "";
}
}
exp.jso_dump = function() {
var key;
for(key in config) {
console.log("=====> Processing provider [" + key + "]");
console.log("=] Config");
console.log(config[key]);
console.log("=] Tokens")
console.log(getTokens(key));
}
}
exp.jso_wipe = function() {
var key;
for(key in config) {
wipeTokens(key);
}
}
exp.jso_getToken = function(providerid, scopes) {
var token = getToken(providerid, scopes);
if (!token) return null;
if (!token["access_token"]) return null;
return token["access_token"];
}
$.oajax = function(settings) {
var
allowia,
scopes,
token,
providerid,
co;
providerid = settings.jso_provider;
allowia = settings.jso_allowia || false;
scopes = settings.jso_scopes;
token = getToken(providerid, scopes);
co = config[providerid];
if (!token) {
if (allowia) {
jso_authrequest(providerid, scopes);
return;
} else {
throw "Could not perform AJAX call because no valid tokens was found.";
}
}
if (co["presenttoken"] && co["presenttoken"] === "qs") {
// settings.url += ((h.indexOf("?") === -1) ? '?' : '&') + "access_token=" + encodeURIComponent(token["access_token"]);
if (!settings.data) settings.data = {};
settings.data["access_token"] = token["access_token"];
} else {
if (!settings.headers) settings.headers = {};
settings.headers["Authorization"] = "Bearer " + token["access_token"];
}
$.ajax(settings);
};
})(window, jQuery);
/*
http://www.JSON.org/json2.js
2011-10-19
Public Domain.
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
See http://www.JSON.org/js.html
This code should be minified before deployment.
See http://javascript.crockford.com/jsmin.html
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
NOT CONTROL.
This file creates a global JSON object containing two methods: stringify
and parse.
JSON.stringify(value, replacer, space)
value any JavaScript value, usually an object or array.
replacer an optional parameter that determines how object
values are stringified for objects. It can be a
function or an array of strings.
space an optional parameter that specifies the indentation
of nested structures. If it is omitted, the text will
be packed without extra whitespace. If it is a number,
it will specify the number of spaces to indent at each
level. If it is a string (such as '\t' or '&nbsp;'),
it contains the characters used to indent at each level.
This method produces a JSON text from a JavaScript value.
When an object value is found, if the object contains a toJSON
method, its toJSON method will be called and the result will be
stringified. A toJSON method does not serialize: it returns the
value represented by the name/value pair that should be serialized,
or undefined if nothing should be serialized. The toJSON method
will be passed the key associated with the value, and this will be
bound to the value
For example, this would serialize Dates as ISO strings.
Date.prototype.toJSON = function (key) {
function f(n) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}
return this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z';
};
You can provide an optional replacer method. It will be passed the
key and value of each member, with this bound to the containing
object. The value that is returned from your method will be
serialized. If your method returns undefined, then the member will
be excluded from the serialization.
If the replacer parameter is an array of strings, then it will be
used to select the members to be serialized. It filters the results
such that only members with keys listed in the replacer array are
stringified.
Values that do not have JSON representations, such as undefined or
functions, will not be serialized. Such values in objects will be
dropped; in arrays they will be replaced with null. You can use
a replacer function to replace those with JSON values.
JSON.stringify(undefined) returns undefined.
The optional space parameter produces a stringification of the
value that is filled with line breaks and indentation to make it
easier to read.
If the space parameter is a non-empty string, then that string will
be used for indentation. If the space parameter is a number, then
the indentation will be that many spaces.
Example:
text = JSON.stringify(['e', {pluribus: 'unum'}]);
// text is '["e",{"pluribus":"unum"}]'
text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
text = JSON.stringify([new Date()], function (key, value) {
return this[key] instanceof Date ?
'Date(' + this[key] + ')' : value;
});
// text is '["Date(---current time---)"]'
JSON.parse(text, reviver)
This method parses a JSON text to produce an object or array.
It can throw a SyntaxError exception.
The optional reviver parameter is a function that can filter and
transform the results. It receives each of the keys and values,
and its return value is used instead of the original value.
If it returns what it received, then the structure is not modified.
If it returns undefined then the member is deleted.
Example:
// Parse the text. Values that look like ISO date strings will
// be converted to Date objects.
myData = JSON.parse(text, function (key, value) {
var a;
if (typeof value === 'string') {
a =
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
if (a) {
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+a[5], +a[6]));
}
}
return value;
});
myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
var d;
if (typeof value === 'string' &&
value.slice(0, 5) === 'Date(' &&
value.slice(-1) === ')') {
d = new Date(value.slice(5, -1));
if (d) {
return d;
}
}
return value;
});
This is a reference implementation. You are free to copy, modify, or
redistribute.
*/
/*jslint evil: true, regexp: true */
/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
lastIndex, length, parse, prototype, push, replace, slice, stringify,
test, toJSON, toString, valueOf
*/
// Create a JSON object only if one does not already exist. We create the
// methods in a closure to avoid creating global variables.
var JSON;
if (!JSON) {
JSON = {};
}
(function () {
'use strict';
function f(n) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}
if (typeof Date.prototype.toJSON !== 'function') {
Date.prototype.toJSON = function (key) {
return isFinite(this.valueOf())
? this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z'
: null;
};
String.prototype.toJSON =
Number.prototype.toJSON =
Boolean.prototype.toJSON = function (key) {
return this.valueOf();
};
}
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
gap,
indent,
meta = { // table of character substitutions
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\f': '\\f',
'\r': '\\r',
'"' : '\\"',
'\\': '\\\\'
},
rep;
function quote(string) {
// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.
escapable.lastIndex = 0;
return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
var c = meta[a];
return typeof c === 'string'
? c
: '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
}) + '"' : '"' + string + '"';
}
function str(key, holder) {
// Produce a string from holder[key].
var i, // The loop counter.
k, // The member key.
v, // The member value.
length,
mind = gap,
partial,
value = holder[key];
// If the value has a toJSON method, call it to obtain a replacement value.
if (value && typeof value === 'object' &&
typeof value.toJSON === 'function') {
value = value.toJSON(key);
}
// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.
if (typeof rep === 'function') {
value = rep.call(holder, key, value);
}
// What happens next depends on the value's type.
switch (typeof value) {
case 'string':
return quote(value);
case 'number':
// JSON numbers must be finite. Encode non-finite numbers as null.
return isFinite(value) ? String(value) : 'null';
case 'boolean':
case 'null':
// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce 'null'. The case is included here in
// the remote chance that this gets fixed someday.
return String(value);
// If the type is 'object', we might be dealing with an object or an array or
// null.
case 'object':
// Due to a specification blunder in ECMAScript, typeof null is 'object',
// so watch out for that case.
if (!value) {
return 'null';
}
// Make an array to hold the partial results of stringifying this object value.
gap += indent;
partial = [];
// Is the value an array?
if (Object.prototype.toString.apply(value) === '[object Array]') {
// The value is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.
length = value.length;
for (i = 0; i < length; i += 1) {
partial[i] = str(i, value) || 'null';
}
// Join all of the elements together, separated with commas, and wrap them in
// brackets.
v = partial.length === 0
? '[]'
: gap
? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']'
: '[' + partial.join(',') + ']';
gap = mind;
return v;
}
// If the replacer is an array, use it to select the members to be stringified.
if (rep && typeof rep === 'object') {
length = rep.length;
for (i = 0; i < length; i += 1) {
if (typeof rep[i] === 'string') {
k = rep[i];
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
} else {
// Otherwise, iterate through all of the keys in the object.
for (k in value) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
}
// Join all of the member texts together, separated with commas,
// and wrap them in braces.
v = partial.length === 0
? '{}'
: gap
? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}'
: '{' + partial.join(',') + '}';
gap = mind;
return v;
}
}
// If the JSON object does not yet have a stringify method, give it one.
if (typeof JSON.stringify !== 'function') {
JSON.stringify = function (value, replacer, space) {
// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
// that can replace values, or an array of strings that will select the keys.
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.
var i;
gap = '';
indent = '';
// If the space parameter is a number, make an indent string containing that
// many spaces.
if (typeof space === 'number') {
for (i = 0; i < space; i += 1) {
indent += ' ';
}
// If the space parameter is a string, it will be used as the indent string.
} else if (typeof space === 'string') {
indent = space;
}
// If there is a replacer, it must be a function or an array.
// Otherwise, throw an error.
rep = replacer;
if (replacer && typeof replacer !== 'function' &&
(typeof replacer !== 'object' ||
typeof replacer.length !== 'number')) {
throw new Error('JSON.stringify');
}
// Make a fake root object containing our value under the key of ''.
// Return the result of stringifying the value.
return str('', {'': value});
};
}
// If the JSON object does not yet have a parse method, give it one.
if (typeof JSON.parse !== 'function') {
JSON.parse = function (text, reviver) {
// The parse method takes a text and an optional reviver function, and returns
// a JavaScript value if the text is a valid JSON text.
var j;
function walk(holder, key) {
// The walk method is used to recursively walk the resulting structure so
// that modifications can be made.
var k, v, value = holder[key];
if (value && typeof value === 'object') {
for (k in value) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
v = walk(value, k);
if (v !== undefined) {
value[k] = v;
} else {
delete value[k];
}
}
}
}
return reviver.call(holder, key, value);
}
// Parsing happens in four stages. In the first stage, we replace certain
// Unicode characters with escape sequences. JavaScript handles many characters
// incorrectly, either silently deleting them, or treating them as line endings.
text = String(text);
cx.lastIndex = 0;
if (cx.test(text)) {
text = text.replace(cx, function (a) {
return '\\u' +
('0000' + a.charCodeAt(0).toString(16)).slice(-4);
});
}
// In the second stage, we run the text against regular expressions that look
// for non-JSON patterns. We are especially concerned with '()' and 'new'
// because they can cause invocation, and '=' because it can cause mutation.
// But just to be safe, we want to reject all unexpected forms.
// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
if (/^[\],:{}\s]*$/
.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
.replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.
j = eval('(' + text + ')');
// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.
return typeof reviver === 'function'
? walk({'': j}, '')
: j;
}
// If the text is not JSON parseable, then a SyntaxError is thrown.
throw new SyntaxError('JSON.parse');
};
}
}());
THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE
("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE
OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS
OF THIS LICENSE. THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE
OF SUCH TERMS AND CONDITIONS.
1. Definitions
a. "Collective Work" means a work, such as a periodical issue, anthology or encyclopedia,
in which the Work in its entirety in unmodified form, along with a number of other
contributions, constituting separate and independent works in themselves, are assembled
into a collective whole. A work that constitutes a Collective Work will not be
considered a Derivative Work (as defined below) for the purposes of this License.
b. "Derivative Work" means a work based upon the Work or upon the Work and other
pre-existing works, such as a translation, musical arrangement, dramatization,
fictionalization, motion picture version, sound recording, art reproduction, abridgment,
condensation, or any other form in which the Work may be recast, transformed, or adapted,
except that a work that constitutes a Collective Work will not be considered a Derivative
Work for the purpose of this License. For the avoidance of doubt, where the Work is a
musical composition or sound recording, the synchronization of the Work in timed-relation
with a moving image ("synching") will be considered a Derivative Work for the purpose of
this License.
c. "Licensor" means the individual or entity that offers the Work under the terms of this
License.
d. "Original Author" means the individual or entity who created the Work.
e. "Work" means the copyrightable work of authorship offered under the terms of this
License.
f. "You" means an individual or entity exercising rights under this License who has not
previously violated the terms of this License with respect to the Work, or who has
received express permission from the Licensor to exercise rights under this License
despite a previous violation.
g. "License Elements" means the following high-level license attributes as selected by
Licensor and indicated in the title of this License: Attribution, ShareAlike.
2. Fair Use Rights. Nothing in this license is intended to reduce, limit, or restrict any rights
arising from fair use, first sale or other limitations on the exclusive rights of the copyright
owner under copyright law or other applicable laws.
3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants
You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable
copyright) license to exercise the rights in the Work as stated below:
a. to reproduce the Work, to incorporate the Work into one or more Collective Works, and to
reproduce the Work as incorporated in the Collective Works;
b. to create and reproduce Derivative Works;
c. to distribute copies or phonorecords of, display publicly, perform publicly, and perform
publicly by means of a digital audio transmission the Work including as incorporated in
Collective Works;
d. to distribute copies or phonorecords of, display publicly, perform publicly, and perform
publicly by means of a digital audio transmission Derivative Works.
e. For the avoidance of doubt, where the work is a musical composition:
i. Performance Royalties Under Blanket Licenses. Licensor waives the exclusive right to
collect, whether individually or via a performance rights society (e.g. ASCAP, BMI,
SESAC), royalties for the public performance or public digital performance (e.g.
webcast) of the Work.
ii. Mechanical Rights and Statutory Royalties. Licensor waives the exclusive right to
collect, whether individually or via a music rights society or designated agent (e.g.
Harry Fox Agency), royalties for any phonorecord You create from the Work ("cover
version") and distribute, subject to the compulsory license created by 17 USC Section
115 of the US Copyright Act (or the equivalent in other jurisdictions).
f. Webcasting Rights and Statutory Royalties. For the avoidance of doubt, where the Work is
a sound recording, Licensor waives the exclusive right to collect, whether individually
or via a performance-rights society (e.g. SoundExchange), royalties for the public
digital performance (e.g. webcast) of the Work, subject to the compulsory license created
by 17 USC Section 114 of the US Copyright Act (or the equivalent in other jurisdictions).
The above rights may be exercised in all media and formats whether now known or hereafter devised.
The above rights include the right to make such modifications as are technically necessary to
exercise the rights in other media and formats. All rights not expressly granted by Licensor are
hereby reserved.
4. Restrictions.The license granted in Section 3 above is expressly made subject to and limited by
the following restrictions:
a. You may distribute, publicly display, publicly perform, or publicly digitally perform the
Work only under the terms of this License, and You must include a copy of, or the Uniform
Resource Identifier for, this License with every copy or phonorecord of the Work You
distribute, publicly display, publicly perform, or publicly digitally perform. You may
not offer or impose any terms on the Work that alter or restrict the terms of this
License or the recipients' exercise of the rights granted hereunder. You may not
sublicense the Work. You must keep intact all notices that refer to this License and to
the disclaimer of warranties. You may not distribute, publicly display, publicly perform,
or publicly digitally perform the Work with any technological measures that control
access or use of the Work in a manner inconsistent with the terms of this License
Agreement. The above applies to the Work as incorporated in a Collective Work, but this
does not require the Collective Work apart from the Work itself to be made subject to the
terms of this License. If You create a Collective Work, upon notice from any Licensor You
must, to the extent practicable, remove from the Collective Work any reference to such
Licensor or the Original Author, as requested. If You create a Derivative Work, upon
notice from any Licensor You must, to the extent practicable, remove from the Derivative
Work any reference to such Licensor or the Original Author, as requested.
b. You may distribute, publicly display, publicly perform, or publicly digitally perform a
Derivative Work only under the terms of this License, a later version of this License
with the same License Elements as this License, or a Creative Commons iCommons license
that contains the same License Elements as this License (e.g. Attribution-ShareAlike 2.0
Japan). You must include a copy of, or the Uniform Resource Identifier for, this License
or other license specified in the previous sentence with every copy or phonorecord of
each Derivative Work You distribute, publicly display, publicly perform, or publicly
digitally perform. You may not offer or impose any terms on the Derivative Works that
alter or restrict the terms of this License or the recipients' exercise of the rights
granted hereunder, and You must keep intact all notices that refer to this License and to
the disclaimer of warranties. You may not distribute, publicly display, publicly perform,
or publicly digitally perform the Derivative Work with any technological measures that
control access or use of the Work in a manner inconsistent with the terms of this License
Agreement. The above applies to the Derivative Work as incorporated in a Collective Work,
but this does not require the Collective Work apart from the Derivative Work itself to be
made subject to the terms of this License.
c. If you distribute, publicly display, publicly perform, or publicly digitally perform the
Work or any Derivative Works or Collective Works, You must keep intact all copyright
notices for the Work and give the Original Author credit reasonable to the medium or
means You are utilizing by conveying the name (or pseudonym if applicable) of the
Original Author if supplied; the title of the Work if supplied; to the extent reasonably
practicable, the Uniform Resource Identifier, if any, that Licensor specifies to be
associated with the Work, unless such URI does not refer to the copyright notice or
licensing information for the Work; and in the case of a Derivative Work, a credit
identifying the use of the Work in the Derivative Work (e.g., "French translation of the
Work by Original Author," or "Screenplay based on original Work by Original Author").
Such credit may be implemented in any reasonable manner; provided, however, that in the
case of a Derivative Work or Collective Work, at a minimum such credit will appear where
any other comparable authorship credit appears and in a manner at least as prominent as
such other comparable authorship credit.
5. Representations, Warranties and Disclaimer
UNLESS OTHERWISE AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO
REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE MATERIALS, EXPRESS, IMPLIED, STATUTORY OR
OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A
PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE
PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE
EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.
6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL
LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE
OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
7. Termination
a. This License and the rights granted hereunder will terminate automatically upon any
breach by You of the terms of this License. Individuals or entities who have received
Derivative Works or Collective Works from You under this License, however, will not have
their licenses terminated provided such individuals or entities remain in full compliance
with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this
License.
b. Subject to the above terms and conditions, the license granted here is perpetual (for the
duration of the applicable copyright in the Work). Notwithstanding the above, Licensor
reserves the right to release the Work under different license terms or to stop
distributing the Work at any time; provided, however that any such election will not
serve to withdraw this License (or any other license that has been, or is required to be,
granted under the terms of this License), and this License will continue in full force
and effect unless terminated as stated above.
8. Miscellaneous
a. Each time You distribute or publicly digitally perform the Work or a Collective Work, the
Licensor offers to the recipient a license to the Work on the same terms and conditions
as the license granted to You under this License.
b. Each time You distribute or publicly digitally perform a Derivative Work, Licensor offers
to the recipient a license to the original Work on the same terms and conditions as the
license granted to You under this License.
c. If any provision of this License is invalid or unenforceable under applicable law, it
shall not affect the validity or enforceability of the remainder of the terms of this
License, and without further action by the parties to this agreement, such provision
shall be reformed to the minimum extent necessary to make such provision valid and
enforceable.
d. No term or provision of this License shall be deemed waived and no breach consented to
unless such waiver or consent shall be in writing and signed by the party to be charged
with such waiver or consent.
e. This License constitutes the entire agreement between the parties with respect to the
Work licensed here. There are no understandings, agreements or representations with
respect to the Work not specified here. Licensor shall not be bound by any additional
provisions that may appear in any communication from You. This License may not be
modified without the mutual written agreement of the Licensor and You.
Creative Commons is not a party to this License, and makes no warranty whatsoever in connection
with the Work. Creative Commons will not be liable to You or any party on any legal theory for
any damages whatsoever, including without limitation any general, special, incidental or
consequential damages arising in connection to this license. Notwithstanding the foregoing two
(2) sentences, if Creative Commons has expressly identified itself as the Licensor hereunder,
it shall have all rights and obligations of Licensor.
Except for the limited purpose of indicating to the public that the Work is licensed under the
CCPL, neither party will use the trademark "Creative Commons" or any related trademark or logo
of Creative Commons without the prior written consent of Creative Commons. Any permitted use will
be in compliance with Creative Commons' then-current trademark usage guidelines, as may be
published on its website or otherwise made available upon request from time to time.
Creative Commons may be contacted at http://creativecommons.org/.
THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE
("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE
OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS
OF THIS LICENSE. THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE
OF SUCH TERMS AND CONDITIONS.
1. Definitions
a. "Collective Work" means a work, such as a periodical issue, anthology or encyclopedia,
in which the Work in its entirety in unmodified form, along with a number of other
contributions, constituting separate and independent works in themselves, are assembled
into a collective whole. A work that constitutes a Collective Work will not be
considered a Derivative Work (as defined below) for the purposes of this License.
b. "Derivative Work" means a work based upon the Work or upon the Work and other
pre-existing works, such as a translation, musical arrangement, dramatization,
fictionalization, motion picture version, sound recording, art reproduction, abridgment,
condensation, or any other form in which the Work may be recast, transformed, or adapted,
except that a work that constitutes a Collective Work will not be considered a Derivative
Work for the purpose of this License. For the avoidance of doubt, where the Work is a
musical composition or sound recording, the synchronization of the Work in timed-relation
with a moving image ("synching") will be considered a Derivative Work for the purpose of
this License.
c. "Licensor" means the individual or entity that offers the Work under the terms of this
License.
d. "Original Author" means the individual or entity who created the Work.
e. "Work" means the copyrightable work of authorship offered under the terms of this
License.
f. "You" means an individual or entity exercising rights under this License who has not
previously violated the terms of this License with respect to the Work, or who has
received express permission from the Licensor to exercise rights under this License
despite a previous violation.
g. "License Elements" means the following high-level license attributes as selected by
Licensor and indicated in the title of this License: Attribution, ShareAlike.
2. Fair Use Rights. Nothing in this license is intended to reduce, limit, or restrict any rights
arising from fair use, first sale or other limitations on the exclusive rights of the copyright
owner under copyright law or other applicable laws.
3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants
You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable
copyright) license to exercise the rights in the Work as stated below:
a. to reproduce the Work, to incorporate the Work into one or more Collective Works, and to
reproduce the Work as incorporated in the Collective Works;
b. to create and reproduce Derivative Works;
c. to distribute copies or phonorecords of, display publicly, perform publicly, and perform
publicly by means of a digital audio transmission the Work including as incorporated in
Collective Works;
d. to distribute copies or phonorecords of, display publicly, perform publicly, and perform
publicly by means of a digital audio transmission Derivative Works.
e. For the avoidance of doubt, where the work is a musical composition:
i. Performance Royalties Under Blanket Licenses. Licensor waives the exclusive right to
collect, whether individually or via a performance rights society (e.g. ASCAP, BMI,
SESAC), royalties for the public performance or public digital performance (e.g.
webcast) of the Work.
ii. Mechanical Rights and Statutory Royalties. Licensor waives the exclusive right to
collect, whether individually or via a music rights society or designated agent (e.g.
Harry Fox Agency), royalties for any phonorecord You create from the Work ("cover
version") and distribute, subject to the compulsory license created by 17 USC Section
115 of the US Copyright Act (or the equivalent in other jurisdictions).
f. Webcasting Rights and Statutory Royalties. For the avoidance of doubt, where the Work is
a sound recording, Licensor waives the exclusive right to collect, whether individually
or via a performance-rights society (e.g. SoundExchange), royalties for the public
digital performance (e.g. webcast) of the Work, subject to the compulsory license created
by 17 USC Section 114 of the US Copyright Act (or the equivalent in other jurisdictions).
The above rights may be exercised in all media and formats whether now known or hereafter devised.
The above rights include the right to make such modifications as are technically necessary to
exercise the rights in other media and formats. All rights not expressly granted by Licensor are
hereby reserved.
4. Restrictions.The license granted in Section 3 above is expressly made subject to and limited by
the following restrictions:
a. You may distribute, publicly display, publicly perform, or publicly digitally perform the
Work only under the terms of this License, and You must include a copy of, or the Uniform
Resource Identifier for, this License with every copy or phonorecord of the Work You
distribute, publicly display, publicly perform, or publicly digitally perform. You may
not offer or impose any terms on the Work that alter or restrict the terms of this
License or the recipients' exercise of the rights granted hereunder. You may not
sublicense the Work. You must keep intact all notices that refer to this License and to
the disclaimer of warranties. You may not distribute, publicly display, publicly perform,
or publicly digitally perform the Work with any technological measures that control
access or use of the Work in a manner inconsistent with the terms of this License
Agreement. The above applies to the Work as incorporated in a Collective Work, but this
does not require the Collective Work apart from the Work itself to be made subject to the
terms of this License. If You create a Collective Work, upon notice from any Licensor You
must, to the extent practicable, remove from the Collective Work any reference to such
Licensor or the Original Author, as requested. If You create a Derivative Work, upon
notice from any Licensor You must, to the extent practicable, remove from the Derivative
Work any reference to such Licensor or the Original Author, as requested.
b. You may distribute, publicly display, publicly perform, or publicly digitally perform a
Derivative Work only under the terms of this License, a later version of this License
with the same License Elements as this License, or a Creative Commons iCommons license
that contains the same License Elements as this License (e.g. Attribution-ShareAlike 2.0
Japan). You must include a copy of, or the Uniform Resource Identifier for, this License
or other license specified in the previous sentence with every copy or phonorecord of
each Derivative Work You distribute, publicly display, publicly perform, or publicly
digitally perform. You may not offer or impose any terms on the Derivative Works that
alter or restrict the terms of this License or the recipients' exercise of the rights
granted hereunder, and You must keep intact all notices that refer to this License and to
the disclaimer of warranties. You may not distribute, publicly display, publicly perform,
or publicly digitally perform the Derivative Work with any technological measures that
control access or use of the Work in a manner inconsistent with the terms of this License
Agreement. The above applies to the Derivative Work as incorporated in a Collective Work,
but this does not require the Collective Work apart from the Derivative Work itself to be
made subject to the terms of this License.
c. If you distribute, publicly display, publicly perform, or publicly digitally perform the
Work or any Derivative Works or Collective Works, You must keep intact all copyright
notices for the Work and give the Original Author credit reasonable to the medium or
means You are utilizing by conveying the name (or pseudonym if applicable) of the
Original Author if supplied; the title of the Work if supplied; to the extent reasonably
practicable, the Uniform Resource Identifier, if any, that Licensor specifies to be
associated with the Work, unless such URI does not refer to the copyright notice or
licensing information for the Work; and in the case of a Derivative Work, a credit
identifying the use of the Work in the Derivative Work (e.g., "French translation of the
Work by Original Author," or "Screenplay based on original Work by Original Author").
Such credit may be implemented in any reasonable manner; provided, however, that in the
case of a Derivative Work or Collective Work, at a minimum such credit will appear where
any other comparable authorship credit appears and in a manner at least as prominent as
such other comparable authorship credit.
5. Representations, Warranties and Disclaimer
UNLESS OTHERWISE AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO
REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE MATERIALS, EXPRESS, IMPLIED, STATUTORY OR
OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A
PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE
PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE
EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.
6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL
LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE
OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
7. Termination
a. This License and the rights granted hereunder will terminate automatically upon any
breach by You of the terms of this License. Individuals or entities who have received
Derivative Works or Collective Works from You under this License, however, will not have
their licenses terminated provided such individuals or entities remain in full compliance
with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this
License.
b. Subject to the above terms and conditions, the license granted here is perpetual (for the
duration of the applicable copyright in the Work). Notwithstanding the above, Licensor
reserves the right to release the Work under different license terms or to stop
distributing the Work at any time; provided, however that any such election will not
serve to withdraw this License (or any other license that has been, or is required to be,
granted under the terms of this License), and this License will continue in full force
and effect unless terminated as stated above.
8. Miscellaneous
a. Each time You distribute or publicly digitally perform the Work or a Collective Work, the
Licensor offers to the recipient a license to the Work on the same terms and conditions
as the license granted to You under this License.
b. Each time You distribute or publicly digitally perform a Derivative Work, Licensor offers
to the recipient a license to the original Work on the same terms and conditions as the
license granted to You under this License.
c. If any provision of this License is invalid or unenforceable under applicable law, it
shall not affect the validity or enforceability of the remainder of the terms of this
License, and without further action by the parties to this agreement, such provision
shall be reformed to the minimum extent necessary to make such provision valid and
enforceable.
d. No term or provision of this License shall be deemed waived and no breach consented to
unless such waiver or consent shall be in writing and signed by the party to be charged
with such waiver or consent.
e. This License constitutes the entire agreement between the parties with respect to the
Work licensed here. There are no understandings, agreements or representations with
respect to the Work not specified here. Licensor shall not be bound by any additional
provisions that may appear in any communication from You. This License may not be
modified without the mutual written agreement of the Licensor and You.
Creative Commons is not a party to this License, and makes no warranty whatsoever in connection
with the Work. Creative Commons will not be liable to You or any party on any legal theory for
any damages whatsoever, including without limitation any general, special, incidental or
consequential damages arising in connection to this license. Notwithstanding the foregoing two
(2) sentences, if Creative Commons has expressly identified itself as the Licensor hereunder,
it shall have all rights and obligations of Licensor.
Except for the limited purpose of indicating to the public that the Work is licensed under the
CCPL, neither party will use the trademark "Creative Commons" or any related trademark or logo
of Creative Commons without the prior written consent of Creative Commons. Any permitted use will
be in compliance with Creative Commons' then-current trademark usage guidelines, as may be
published on its website or otherwise made available upon request from time to time.
Creative Commons may be contacted at http://creativecommons.org/.
(function(){if(!this.localStorage)if(this.globalStorage)try{this.localStorage=this.globalStorage}catch(e){}else{var a=document.createElement("div");a.style.display="none";document.getElementsByTagName("head")[0].appendChild(a);if(a.addBehavior){a.addBehavior("#default#userdata");var d=this.localStorage={length:0,setItem:function(b,d){a.load("localStorage");b=c(b);a.getAttribute(b)||this.length++;a.setAttribute(b,d);a.save("localStorage")},getItem:function(b){a.load("localStorage");b=c(b);return a.getAttribute(b)},
removeItem:function(b){a.load("localStorage");b=c(b);a.removeAttribute(b);a.save("localStorage");this.length--;if(0>this.length)this.length=0},clear:function(){a.load("localStorage");for(var b=0;attr=a.XMLDocument.documentElement.attributes[b++];)a.removeAttribute(attr.name);a.save("localStorage");this.length=0},key:function(b){a.load("localStorage");return a.XMLDocument.documentElement.attributes[b]}},c=function(a){return a.replace(/[^-._0-9A-Za-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u37f-\u1fff\u200c-\u200d\u203f\u2040\u2070-\u218f]/g,
"-")};a.load("localStorage");d.length=a.XMLDocument.documentElement.attributes.length}}})();
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Sparklr</title>
<link type="text/css" rel="stylesheet"
href="<c:url value="/style.css"/>" />
</head>
<body>
<h1>Sparklr</h1>
<div id="content">
<c:if test="${not empty param.authentication_error}">
<h1>Woops!</h1>
<p class="error">Your login attempt was not successful.</p>
</c:if>
<c:if test="${not empty param.authorization_error}">
<h1>Woops!</h1>
<p class="error">You are not permitted to access that resource.</p>
</c:if>
<h2>Login</h2>
<p>We've got a grand total of 2 users: marissa and paul. Go ahead
and log in. Marissa's password is "koala" and Paul's password is
"emu".</p>
<form id="loginForm" name="loginForm"
action="<c:url value="/login.do"/>" method="post">
<p>
<label>Username: <input type='text' name='j_username'
value="marissa" /></label>
</p>
<p>
<label>Password: <input type='text' name='j_password'
value="koala" /></label>
</p>
<p>
<input name="login" value="Login" type="submit"/>
</p>
</form>
</div>
<div id="footer">
Sample application for <a
href="http://github.com/SpringSource/spring-security-oauth"
target="_blank">Spring Security OAuth</a>
</div>
</body>
</html>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link href="<c:url value="/main.css"/>" rel="stylesheet" type="text/css" />
<title>tonr</title>
</head>
<body>
<div id="container">
<ul id="mainlinks">
<li><a href="<c:url value="/index.jsp"/>">home</a></li>
<li><a href="<c:url value="/login.jsp"/>" class="selected">login</a></li>
<li><a href="<c:url value="/sparklr/photos"/>">sparklr pics</a></li>
<li><a href="<c:url value="/facebook/info"/>">facebook
friends</a></li>
</ul>
<div id="content">
<c:if test="${not empty param.authentication_error}">
<h1>Woops!</h1>
<p class="error">Your login attempt was not successful.</p>
</c:if>
<c:if test="${not empty param.authorization_error}">
<h1>Woops!</h1>
<p class="error">You are not permitted to access that resource.</p>
</c:if>
<h1>Login</h1>
<p>Tonr.com has only two users: "marissa" and "sam". The password
for "marissa" is password is "wombat" and for "sam" is password is
"kangaroo".</p>
<form action="<c:url value="/login.do"/>" method="post">
<p>
<label>Username: <input type='text' name='j_username'
value="marissa"/></label>
</p>
<p>
<label>Password: <input type='text' name='j_password'
value="wombat"/></label>
</p>
<p>
<input name="login" value="Login" type="submit"/>
</p>
</form>
<p class="footer">
Courtesy <a href="http://www.openwebdesign.org">Open Web Design</a>
Thanks to <a href="http://www.dubaiapartments.biz/">Dubai Hotels</a>
</p>
</div>
</div>
</body>
</html>
body {
font-size: 10pt;
letter-spacing: 1px;
background: url( images/xbg.gif ) no-repeat;
font-family: Helvetica, Arial, sans-serif;
word-spacing: 5px;
color: #515151;
}
#container {
margin: 100px auto 0 auto;
width: 855px;
}
#content {
background-color: #f7f7f7;
padding: 20px 0 20px 20px;
}
#mainlinks {
height: 60px;
list-style: none;
margin: 0;
}
#mainlinks li {
float: right;
margin-right: 10px;
list-style-type: none;
list-style-image: none;
}
#mainlinks li a {
padding: 30px 0 0 0;
background: #d0d0d0;
display: block;
padding-top: 10px;
width: 100px;
height: 50px;
text-align: center;
color: #515151;
text-decoration: none;
}
#mainlinks li a:hover {
background: #f7f7f7;
}
#mainlinks li a.selected {
background: #f7f7f7;
color: #515151;
}
p {
line-height: 1.4em;
}
p.error {
color: red;
}
h1 {
padding: 25px 0 5px 0;
}
#picturelist {
text-align: left;
margin-right: auto;
margin-left: auto;
}
#picturelist li {
list-style: none;
margin: 42px;
font-weight: bold;
color: #777777;
}
#picturelist img {
display: block;
border: 2px solid gray;
}
#picturelist img:hover {
border: 2px solid #515151;
}
#picturelist a {
color: #777777;
text-decoration: none;
}
#picturelist a:hover {
color: #999999;
}
.footer {
margin-top: 100px;
font-size: .8em;
text-align:center;
}
/* Modernizr 2.5.3 (Custom Build) | MIT & BSD
* Build: http://www.modernizr.com/download/#-fontface-backgroundsize-borderimage-borderradius-boxshadow-flexbox-hsla-multiplebgs-opacity-rgba-textshadow-cssanimations-csscolumns-generatedcontent-cssgradients-cssreflections-csstransforms-csstransforms3d-csstransitions-applicationcache-canvas-canvastext-draganddrop-hashchange-history-audio-video-indexeddb-input-inputtypes-localstorage-postmessage-sessionstorage-websockets-websqldatabase-webworkers-geolocation-inlinesvg-smil-svg-svgclippaths-touch-webgl-shiv-mq-cssclasses-addtest-prefixed-teststyles-testprop-testallprops-hasevent-prefixes-domprefixes-load
*/
;window.Modernizr=function(a,b,c){function D(a){j.cssText=a}function E(a,b){return D(n.join(a+";")+(b||""))}function F(a,b){return typeof a===b}function G(a,b){return!!~(""+a).indexOf(b)}function H(a,b){for(var d in a)if(j[a[d]]!==c)return b=="pfx"?a[d]:!0;return!1}function I(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:F(f,"function")?f.bind(d||b):f}return!1}function J(a,b,c){var d=a.charAt(0).toUpperCase()+a.substr(1),e=(a+" "+p.join(d+" ")+d).split(" ");return F(b,"string")||F(b,"undefined")?H(e,b):(e=(a+" "+q.join(d+" ")+d).split(" "),I(e,b,c))}function L(){e.input=function(c){for(var d=0,e=c.length;d<e;d++)u[c[d]]=c[d]in k;return u.list&&(u.list=!!b.createElement("datalist")&&!!a.HTMLDataListElement),u}("autocomplete autofocus list placeholder max min multiple pattern required step".split(" ")),e.inputtypes=function(a){for(var d=0,e,f,h,i=a.length;d<i;d++)k.setAttribute("type",f=a[d]),e=k.type!=="text",e&&(k.value=l,k.style.cssText="position:absolute;visibility:hidden;",/^range$/.test(f)&&k.style.WebkitAppearance!==c?(g.appendChild(k),h=b.defaultView,e=h.getComputedStyle&&h.getComputedStyle(k,null).WebkitAppearance!=="textfield"&&k.offsetHeight!==0,g.removeChild(k)):/^(search|tel)$/.test(f)||(/^(url|email)$/.test(f)?e=k.checkValidity&&k.checkValidity()===!1:/^color$/.test(f)?(g.appendChild(k),g.offsetWidth,e=k.value!=l,g.removeChild(k)):e=k.value!=l)),t[a[d]]=!!e;return t}("search tel url email datetime date month week time datetime-local number range color".split(" "))}var d="2.5.3",e={},f=!0,g=b.documentElement,h="modernizr",i=b.createElement(h),j=i.style,k=b.createElement("input"),l=":)",m={}.toString,n=" -webkit- -moz- -o- -ms- ".split(" "),o="Webkit Moz O ms",p=o.split(" "),q=o.toLowerCase().split(" "),r={svg:"http://www.w3.org/2000/svg"},s={},t={},u={},v=[],w=v.slice,x,y=function(a,c,d,e){var f,i,j,k=b.createElement("div"),l=b.body,m=l?l:b.createElement("body");if(parseInt(d,10))while(d--)j=b.createElement("div"),j.id=e?e[d]:h+(d+1),k.appendChild(j);return f=["&#173;","<style>",a,"</style>"].join(""),k.id=h,m.innerHTML+=f,m.appendChild(k),l||(m.style.background="",g.appendChild(m)),i=c(k,a),l?k.parentNode.removeChild(k):m.parentNode.removeChild(m),!!i},z=function(b){var c=a.matchMedia||a.msMatchMedia;if(c)return c(b).matches;var d;return y("@media "+b+" { #"+h+" { position: absolute; } }",function(b){d=(a.getComputedStyle?getComputedStyle(b,null):b.currentStyle)["position"]=="absolute"}),d},A=function(){function d(d,e){e=e||b.createElement(a[d]||"div"),d="on"+d;var f=d in e;return f||(e.setAttribute||(e=b.createElement("div")),e.setAttribute&&e.removeAttribute&&(e.setAttribute(d,""),f=F(e[d],"function"),F(e[d],"undefined")||(e[d]=c),e.removeAttribute(d))),e=null,f}var a={select:"input",change:"input",submit:"form",reset:"form",error:"img",load:"img",abort:"img"};return d}(),B={}.hasOwnProperty,C;!F(B,"undefined")&&!F(B.call,"undefined")?C=function(a,b){return B.call(a,b)}:C=function(a,b){return b in a&&F(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;var d=w.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(w.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(w.call(arguments)))};return e});var K=function(c,d){var f=c.join(""),g=d.length;y(f,function(c,d){var f=b.styleSheets[b.styleSheets.length-1],h=f?f.cssRules&&f.cssRules[0]?f.cssRules[0].cssText:f.cssText||"":"",i=c.childNodes,j={};while(g--)j[i[g].id]=i[g];e.touch="ontouchstart"in a||a.DocumentTouch&&b instanceof DocumentTouch||(j.touch&&j.touch.offsetTop)===9,e.csstransforms3d=(j.csstransforms3d&&j.csstransforms3d.offsetLeft)===9&&j.csstransforms3d.offsetHeight===3,e.generatedcontent=(j.generatedcontent&&j.generatedcontent.offsetHeight)>=1,e.fontface=/src/i.test(h)&&h.indexOf(d.split(" ")[0])===0},g,d)}(['@font-face {font-family:"font";src:url("https://")}',["@media (",n.join("touch-enabled),("),h,")","{#touch{top:9px;position:absolute}}"].join(""),["@media (",n.join("transform-3d),("),h,")","{#csstransforms3d{left:9px;position:absolute;height:3px;}}"].join(""),['#generatedcontent:after{content:"',l,'";visibility:hidden}'].join("")],["fontface","touch","csstransforms3d","generatedcontent"]);s.flexbox=function(){return J("flexOrder")},s.canvas=function(){var a=b.createElement("canvas");return!!a.getContext&&!!a.getContext("2d")},s.canvastext=function(){return!!e.canvas&&!!F(b.createElement("canvas").getContext("2d").fillText,"function")},s.webgl=function(){try{var d=b.createElement("canvas"),e;e=!(!a.WebGLRenderingContext||!d.getContext("experimental-webgl")&&!d.getContext("webgl")),d=c}catch(f){e=!1}return e},s.touch=function(){return e.touch},s.geolocation=function(){return!!navigator.geolocation},s.postmessage=function(){return!!a.postMessage},s.websqldatabase=function(){return!!a.openDatabase},s.indexedDB=function(){return!!J("indexedDB",a)},s.hashchange=function(){return A("hashchange",a)&&(b.documentMode===c||b.documentMode>7)},s.history=function(){return!!a.history&&!!history.pushState},s.draganddrop=function(){var a=b.createElement("div");return"draggable"in a||"ondragstart"in a&&"ondrop"in a},s.websockets=function(){for(var b=-1,c=p.length;++b<c;)if(a[p[b]+"WebSocket"])return!0;return"WebSocket"in a},s.rgba=function(){return D("background-color:rgba(150,255,150,.5)"),G(j.backgroundColor,"rgba")},s.hsla=function(){return D("background-color:hsla(120,40%,100%,.5)"),G(j.backgroundColor,"rgba")||G(j.backgroundColor,"hsla")},s.multiplebgs=function(){return D("background:url(https://),url(https://),red url(https://)"),/(url\s*\(.*?){3}/.test(j.background)},s.backgroundsize=function(){return J("backgroundSize")},s.borderimage=function(){return J("borderImage")},s.borderradius=function(){return J("borderRadius")},s.boxshadow=function(){return J("boxShadow")},s.textshadow=function(){return b.createElement("div").style.textShadow===""},s.opacity=function(){return E("opacity:.55"),/^0.55$/.test(j.opacity)},s.cssanimations=function(){return J("animationName")},s.csscolumns=function(){return J("columnCount")},s.cssgradients=function(){var a="background-image:",b="gradient(linear,left top,right bottom,from(#9f9),to(white));",c="linear-gradient(left top,#9f9, white);";return D((a+"-webkit- ".split(" ").join(b+a)+n.join(c+a)).slice(0,-a.length)),G(j.backgroundImage,"gradient")},s.cssreflections=function(){return J("boxReflect")},s.csstransforms=function(){return!!J("transform")},s.csstransforms3d=function(){var a=!!J("perspective");return a&&"webkitPerspective"in g.style&&(a=e.csstransforms3d),a},s.csstransitions=function(){return J("transition")},s.fontface=function(){return e.fontface},s.generatedcontent=function(){return e.generatedcontent},s.video=function(){var a=b.createElement("video"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('video/ogg; codecs="theora"').replace(/^no$/,""),c.h264=a.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/,""),c.webm=a.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,"")}catch(d){}return c},s.audio=function(){var a=b.createElement("audio"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),c.mp3=a.canPlayType("audio/mpeg;").replace(/^no$/,""),c.wav=a.canPlayType('audio/wav; codecs="1"').replace(/^no$/,""),c.m4a=(a.canPlayType("audio/x-m4a;")||a.canPlayType("audio/aac;")).replace(/^no$/,"")}catch(d){}return c},s.localstorage=function(){try{return localStorage.setItem(h,h),localStorage.removeItem(h),!0}catch(a){return!1}},s.sessionstorage=function(){try{return sessionStorage.setItem(h,h),sessionStorage.removeItem(h),!0}catch(a){return!1}},s.webworkers=function(){return!!a.Worker},s.applicationcache=function(){return!!a.applicationCache},s.svg=function(){return!!b.createElementNS&&!!b.createElementNS(r.svg,"svg").createSVGRect},s.inlinesvg=function(){var a=b.createElement("div");return a.innerHTML="<svg/>",(a.firstChild&&a.firstChild.namespaceURI)==r.svg},s.smil=function(){return!!b.createElementNS&&/SVGAnimate/.test(m.call(b.createElementNS(r.svg,"animate")))},s.svgclippaths=function(){return!!b.createElementNS&&/SVGClipPath/.test(m.call(b.createElementNS(r.svg,"clipPath")))};for(var M in s)C(s,M)&&(x=M.toLowerCase(),e[x]=s[M](),v.push((e[x]?"":"no-")+x));return e.input||L(),e.addTest=function(a,b){if(typeof a=="object")for(var d in a)C(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return e;b=typeof b=="function"?b():b,g.className+=" "+(b?"":"no-")+a,e[a]=b}return e},D(""),i=k=null,function(a,b){function g(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x<style>"+b+"</style>",d.insertBefore(c.lastChild,d.firstChild)}function h(){var a=k.elements;return typeof a=="string"?a.split(" "):a}function i(a){var b={},c=a.createElement,e=a.createDocumentFragment,f=e();a.createElement=function(a){var e=(b[a]||(b[a]=c(a))).cloneNode();return k.shivMethods&&e.canHaveChildren&&!d.test(a)?f.appendChild(e):e},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+h().join().replace(/\w+/g,function(a){return b[a]=c(a),f.createElement(a),'c("'+a+'")'})+");return n}")(k,f)}function j(a){var b;return a.documentShived?a:(k.shivCSS&&!e&&(b=!!g(a,"article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio{display:none}canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden]{display:none}audio[controls]{display:inline-block;*display:inline;*zoom:1}mark{background:#FF0;color:#000}")),f||(b=!i(a)),b&&(a.documentShived=b),a)}var c=a.html5||{},d=/^<|^(?:button|form|map|select|textarea)$/i,e,f;(function(){var a=b.createElement("a");a.innerHTML="<xyz></xyz>",e="hidden"in a,f=a.childNodes.length==1||function(){try{b.createElement("a")}catch(a){return!0}var c=b.createDocumentFragment();return typeof c.cloneNode=="undefined"||typeof c.createDocumentFragment=="undefined"||typeof c.createElement=="undefined"}()})();var k={elements:c.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",shivCSS:c.shivCSS!==!1,shivMethods:c.shivMethods!==!1,type:"default",shivDocument:j};a.html5=k,j(b)}(this,b),e._version=d,e._prefixes=n,e._domPrefixes=q,e._cssomPrefixes=p,e.mq=z,e.hasEvent=A,e.testProp=function(a){return H([a])},e.testAllProps=J,e.testStyles=y,e.prefixed=function(a,b,c){return b?J(a,b,c):J(a,"pfx")},g.className=g.className.replace(/(^|\s)no-js(\s|$)/,"$1$2")+(f?" js "+v.join(" "):""),e}(this,this.document),function(a,b,c){function d(a){return o.call(a)=="[object Function]"}function e(a){return typeof a=="string"}function f(){}function g(a){return!a||a=="loaded"||a=="complete"||a=="uninitialized"}function h(){var a=p.shift();q=1,a?a.t?m(function(){(a.t=="c"?B.injectCss:B.injectJs)(a.s,0,a.a,a.x,a.e,1)},0):(a(),h()):q=0}function i(a,c,d,e,f,i,j){function k(b){if(!o&&g(l.readyState)&&(u.r=o=1,!q&&h(),l.onload=l.onreadystatechange=null,b)){a!="img"&&m(function(){t.removeChild(l)},50);for(var d in y[c])y[c].hasOwnProperty(d)&&y[c][d].onload()}}var j=j||B.errorTimeout,l={},o=0,r=0,u={t:d,s:c,e:f,a:i,x:j};y[c]===1&&(r=1,y[c]=[],l=b.createElement(a)),a=="object"?l.data=c:(l.src=c,l.type=a),l.width=l.height="0",l.onerror=l.onload=l.onreadystatechange=function(){k.call(this,r)},p.splice(e,0,u),a!="img"&&(r||y[c]===2?(t.insertBefore(l,s?null:n),m(k,j)):y[c].push(l))}function j(a,b,c,d,f){return q=0,b=b||"j",e(a)?i(b=="c"?v:u,a,b,this.i++,c,d,f):(p.splice(this.i++,0,a),p.length==1&&h()),this}function k(){var a=B;return a.loader={load:j,i:0},a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=s?l:n.parentNode,l=a.opera&&o.call(a.opera)=="[object Opera]",l=!!b.attachEvent&&!l,u=r?"object":l?"script":"img",v=l?"script":u,w=Array.isArray||function(a){return o.call(a)=="[object Array]"},x=[],y={},z={timeout:function(a,b){return b.length&&(a.timeout=b[0]),a}},A,B;B=function(a){function b(a){var a=a.split("!"),b=x.length,c=a.pop(),d=a.length,c={url:c,origUrl:c,prefixes:a},e,f,g;for(f=0;f<d;f++)g=a[f].split("="),(e=z[g.shift()])&&(c=e(c,g));for(f=0;f<b;f++)c=x[f](c);return c}function g(a,e,f,g,i){var j=b(a),l=j.autoCallback;j.url.split(".").pop().split("?").shift(),j.bypass||(e&&(e=d(e)?e:e[a]||e[g]||e[a.split("/").pop().split("?")[0]]||h),j.instead?j.instead(a,e,f,g,i):(y[j.url]?j.noexec=!0:y[j.url]=1,f.load(j.url,j.forceCSS||!j.forceJS&&"css"==j.url.split(".").pop().split("?").shift()?"c":c,j.noexec,j.attrs,j.timeout),(d(e)||d(l))&&f.load(function(){k(),e&&e(j.origUrl,i,g),l&&l(j.origUrl,i,g),y[j.url]=2})))}function i(a,b){function c(a,c){if(a){if(e(a))c||(j=function(){var a=[].slice.call(arguments);k.apply(this,a),l()}),g(a,j,b,0,h);else if(Object(a)===a)for(n in m=function(){var b=0,c;for(c in a)a.hasOwnProperty(c)&&b++;return b}(),a)a.hasOwnProperty(n)&&(!c&&!--m&&(d(j)?j=function(){var a=[].slice.call(arguments);k.apply(this,a),l()}:j[n]=function(a){return function(){var b=[].slice.call(arguments);a&&a.apply(this,b),l()}}(k[n])),g(a[n],j,b,n,h))}else!c&&l()}var h=!!a.test,i=a.load||a.both,j=a.callback||f,k=j,l=a.complete||f,m,n;c(h?a.yep:a.nope,!!i),i&&c(i)}var j,l,m=this.yepnope.loader;if(e(a))g(a,0,m,0);else if(w(a))for(j=0;j<a.length;j++)l=a[j],e(l)?g(l,0,m,0):w(l)?B(l):Object(l)===l&&i(l,m);else Object(a)===a&&i(a,m)},B.addPrefix=function(a,b){z[a]=b},B.addFilter=function(a){x.push(a)},B.errorTimeout=1e4,b.readyState==null&&b.addEventListener&&(b.readyState="loading",b.addEventListener("DOMContentLoaded",A=function(){b.removeEventListener("DOMContentLoaded",A,0),b.readyState="complete"},0)),a.yepnope=k(),a.yepnope.executeStack=h,a.yepnope.injectJs=function(a,c,d,e,i,j){var k=b.createElement("script"),l,o,e=e||B.errorTimeout;k.src=a;for(o in d)k.setAttribute(o,d[o]);c=j?h:c||f,k.onreadystatechange=k.onload=function(){!l&&g(k.readyState)&&(l=1,c(),k.onload=k.onreadystatechange=null)},m(function(){l||(l=1,c(1))},e),i?k.onload():n.parentNode.insertBefore(k,n)},a.yepnope.injectCss=function(a,c,d,e,g,i){var e=b.createElement("link"),j,c=i?h:c||f;e.href=a,e.rel="stylesheet",e.type="text/css";for(j in d)e.setAttribute(j,d[j]);g||(n.parentNode.insertBefore(e,n),m(c,0))}}(this,document),Modernizr.load=function(){yepnope.apply(window,[].slice.call(arguments,0))};
<%@ page import="java.io.PrintWriter" %>
<%@ page import="java.io.StringWriter" %>
<%@ taglib prefix="authz" uri="http://www.springframework.org/security/tags" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link href="<c:url value="/main.css"/>" rel="stylesheet" type="text/css"/>
<title>tonr</title>
</head>
<body>
<div id="container">
<ul id="mainlinks">
<li><a href="<c:url value="/index.jsp"/>">home</a></li>
<authz:authorize ifNotGranted="ROLE_USER">
<li><a href="<c:url value="/login.jsp"/>">login</a></li>
</authz:authorize>
<li><a href="<c:url value="/sparklr/photos"/>">sparklr pics</a></li>
<li><a href="<c:url value="/facebook/info"/>">facebook friends</a></li>
</ul>
<div id="content">
<p class="footer">Courtesy <a href="http://www.openwebdesign.org">Open Web Design</a> Thanks to <a
href="http://www.dubaiapartments.biz/">Dubai Hotels</a></p>
</div>
</div>
</body>
</html>
package org.springframework.security.oauth.examples.sparklr.mvc;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.Principal;
import java.util.Collection;
import java.util.Iterator;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.oauth.examples.sparklr.PhotoInfo;
import org.springframework.security.oauth.examples.sparklr.PhotoService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* @author Ryan Heaton
* @author Dave Syer
*/
@Controller
public class PhotoController {
private PhotoService photoService;
@RequestMapping("/photos/{photoId}")
public ResponseEntity<byte[]> getPhoto(@PathVariable("photoId") String id) throws IOException {
InputStream photo = getPhotoService().loadPhoto(id);
if (photo == null) {
return new ResponseEntity<byte[]>(HttpStatus.NOT_FOUND);
} else {
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = photo.read(buffer);
while (len >= 0) {
out.write(buffer, 0, len);
len = photo.read(buffer);
}
HttpHeaders headers = new HttpHeaders();
headers.set("Content-Type", "image/jpeg");
return new ResponseEntity<byte[]>(out.toByteArray(), headers, HttpStatus.OK);
}
}
@RequestMapping(value = "/photos", params = "format=json")
public ResponseEntity<String> getJsonPhotos(@RequestParam(value = "callback", required = false) String callback, Principal principal) {
Collection<PhotoInfo> photos = getPhotoService().getPhotosForCurrentUser(principal.getName());
StringBuilder out = new StringBuilder();
if (callback != null) {
out.append(callback).append("( ");
}
out.append("{ \"photos\" : [ ");
Iterator<PhotoInfo> photosIt = photos.iterator();
while (photosIt.hasNext()) {
PhotoInfo photo = photosIt.next();
out.append(String.format("{ \"id\" : \"%s\" , \"name\" : \"%s\" }", photo.getId(), photo.getName()));
if (photosIt.hasNext()) {
out.append(" , ");
}
}
out.append("] }");
if (callback != null) {
out.append(" )");
}
HttpHeaders headers = new HttpHeaders();
headers.set("Content-Type", "application/json");
return new ResponseEntity<String>(out.toString(), headers, HttpStatus.OK);
}
@RequestMapping(value = "/photos", params = "format=xml")
public ResponseEntity<String> getXmlPhotos(Principal principal) {
Collection<PhotoInfo> photos = photoService.getPhotosForCurrentUser(principal.getName());
StringBuilder out = new StringBuilder();
out.append("<photos>");
for (PhotoInfo photo : photos) {
out.append(String.format("<photo id=\"%s\" name=\"%s\"/>", photo.getId(), photo.getName()));
}
out.append("</photos>");
HttpHeaders headers = new HttpHeaders();
headers.set("Content-Type", "application/xml");
return new ResponseEntity<String>(out.toString(), headers, HttpStatus.OK);
}
@RequestMapping("/photos/trusted/message")
@PreAuthorize("oauthClientHasRole('ROLE_CLIENT')")
@ResponseBody
public String getTrustedClientMessage() {
return "Hello, Trusted Client";
}
@RequestMapping("/photos/user/message")
@ResponseBody
public String getTrustedUserMessage(Principal principal) {
return "Hello, Trusted User" + (principal!=null ? " " + principal.getName() : "");
}
public PhotoService getPhotoService() {
return photoService;
}
public void setPhotoService(PhotoService photoService) {
this.photoService = photoService;
}
}
package org.springframework.security.oauth.examples.sparklr;
/**
* Photo information.
*
* @author Ryan Heaton
*/
public class PhotoInfo {
private String id;
private String resourceURL;
private String name;
private String userId;
/**
* Id of the photo.
*
* @return Id of the photo.
*/
public String getId() {
return id;
}
/**
* Id of the photo.
*
* @param id Id of the photo.
*/
public void setId(String id) {
this.id = id;
}
/**
* The resource URL.
*
* @return The resource URL.
*/
public String getResourceURL() {
return resourceURL;
}
/**
* The resource URL.
*
* @param resourceURL The resource URL
*/
public void setResourceURL(String resourceURL) {
this.resourceURL = resourceURL;
}
/**
* Name of the photo.
*
* @return Name of the photo.
*/
public String getName() {
return name;
}
/**
* Name of the photo.
*
* @param name Name of the photo.
*/
public void setName(String name) {
this.name = name;
}
/**
* The id of the user to whom the photo belongs.
*
* @return The id of the user to whom the photo belongs.
*/
public String getUserId() {
return userId;
}
/**
* The id of the user to whom the photo belongs.
*
* @param userId The id of the user to whom the photo belongs.
*/
public void setUserId(String userId) {
this.userId = userId;
}
}
package org.springframework.security.oauth.examples.sparklr;
import java.util.Collection;
import java.io.InputStream;
/**
* Service for retrieving photos.
*
* @author Ryan Heaton
*/
public interface PhotoService {
/**
* Load the photos for the current user.
*
* @return The photos for the current user.
*/
Collection<PhotoInfo> getPhotosForCurrentUser(String username);
/**
* Load a photo by id.
*
* @param id The id of the photo.
* @return The photo that was read.
*/
InputStream loadPhoto(String id);
}
package org.springframework.security.oauth.examples.sparklr.impl;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.oauth.examples.sparklr.PhotoInfo;
import org.springframework.security.oauth.examples.sparklr.PhotoService;
/**
* Basic implementation for the photo service.
*
* @author Ryan Heaton
*/
public class PhotoServiceImpl implements PhotoService {
private List<PhotoInfo> photos;
public Collection<PhotoInfo> getPhotosForCurrentUser(String username) {
ArrayList<PhotoInfo> infos = new ArrayList<PhotoInfo>();
for (PhotoInfo info : getPhotos()) {
if (username.equals(info.getUserId())) {
infos.add(info);
}
}
return infos;
}
public InputStream loadPhoto(String id) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication.getPrincipal() instanceof UserDetails) {
UserDetails details = (UserDetails) authentication.getPrincipal();
String username = details.getUsername();
for (PhotoInfo photoInfo : getPhotos()) {
if (id.equals(photoInfo.getId()) && username.equals(photoInfo.getUserId())) {
URL resourceURL = getClass().getResource(photoInfo.getResourceURL());
if (resourceURL != null) {
try {
return resourceURL.openStream();
} catch (IOException e) {
// fall through...
}
}
}
}
}
return null;
}
public List<PhotoInfo> getPhotos() {
return photos;
}
public void setPhotos(List<PhotoInfo> photos) {
this.photos = photos;
}
}
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth-parent</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
<relativePath>../../..</relativePath>
</parent>
<artifactId>sparklr2</artifactId>
<packaging>war</packaging>
<name>OAuth for Spring Security - Sparklr2 (OAuth 2 Provider Example)</name>
<properties>
<m2eclipse.wtp.contextRoot>/sparklr2</m2eclipse.wtp.contextRoot>
</properties>
<profiles>
<profile>
<id>integration</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.7.1</version>
<executions>
<execution>
<id>surefire-it</id>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<skip>${skipTests}</skip>
<testFailureIgnore>true</testFailureIgnore>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>tomcat-maven-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<id>start-tomcat</id>
<phase>pre-integration-test</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<fork>true</fork>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<build>
<plugins>
<plugin>
<!--skip deploy (this is just a test module) -->
<artifactId>maven-deploy-plugin</artifactId>
<version>2.6</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>tomcat-maven-plugin</artifactId>
<configuration>
<addContextWarDependencies>true</addContextWarDependencies>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
<repositories>
<repository>
<id>spring-milestone</id>
<name>Spring Framework Milestone Repository</name>
<url>http://maven.springframework.org/milestone</url>
</repository>
<repository>
<id>spring-release</id>
<name>Spring Framework Release Repository</name>
<url>http://maven.springframework.org/release</url>
</repository>
<repository>
<id>java.net</id>
<url>http://download.java.net/maven/2</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.8.3</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.1.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<!-- <profiles> <profile> <id>gae</id> <dependencies> <dependency> <groupId>com.google.appengine</groupId> <artifactId>appengine-api-1.0-sdk</artifactId>
<version>1.2.2</version> </dependency> </dependencies> </profile> </profiles> -->
</project>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth-parent</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
<relativePath>../../..</relativePath>
</parent>
<artifactId>tonr2</artifactId>
<packaging>war</packaging>
<name>OAuth for Spring Security - Tonr2 (OAuth 2 Client Example)</name>
<properties>
<m2eclipse.wtp.contextRoot>/tonr2</m2eclipse.wtp.contextRoot>
</properties>
<profiles>
<profile>
<id>integration</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.7.1</version>
<executions>
<execution>
<id>surefire-it</id>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<skip>${skipTests}</skip>
<testFailureIgnore>true</testFailureIgnore>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>tomcat-maven-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<id>start-tomcat</id>
<phase>pre-integration-test</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<fork>true</fork>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<build>
<plugins>
<plugin>
<!--skip deploy (this is just a test module) -->
<artifactId>maven-deploy-plugin</artifactId>
<version>2.6</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>tomcat-maven-plugin</artifactId>
<configuration>
<addContextWarDependencies>true</addContextWarDependencies>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
<repositories>
<repository>
<id>spring-milestone</id>
<name>Spring Framework Milestone Repository</name>
<url>http://maven.springframework.org/milestone</url>
</repository>
<repository>
<id>spring-release</id>
<name>Spring Framework Release Repository</name>
<url>http://maven.springframework.org/release</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>${pom.groupId}</groupId>
<artifactId>sparklr2</artifactId>
<version>${pom.version}</version>
<type>war</type>
<scope>tomcat</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.5.5</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
<%@ taglib prefix="authz" uri="http://www.springframework.org/security/tags" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"/>
<title>Sparklr</title>
<link type="text/css" rel="stylesheet" href="<c:url value="/style.css"/>"/>
</head>
<body>
<h1>Sparklr</h1>
<div id="content">
<h2>Home</h2>
<p>You have successfully authorized the request for a protected resource.</p>
</div>
<div id="footer">Sample application for <a href="http://github.com/SpringSource/spring-security-oauth" target="_blank">Spring Security OAuth</a></div>
</body>
</html>
package org.springframework.security.oauth2.provider;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URI;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.client.HttpClient;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.client.params.CookiePolicy;
import org.junit.Assume;
import org.junit.internal.AssumptionViolatedException;
import org.junit.rules.MethodRule;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.Statement;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.security.oauth2.client.test.RestTemplateHolder;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestOperations;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriTemplate;
/**
* <p>
* A rule that prevents integration tests from failing if the server application is not running or not accessible. If
* the server is not running in the background all the tests here will simply be skipped because of a violated
* assumption (showing as successful). Usage:
* </p>
*
* <pre>
* &#064;Rule public static BrokerRunning brokerIsRunning = BrokerRunning.isRunning();
*
* &#064;Test public void testSendAndReceive() throws Exception { // ... test using RabbitTemplate etc. }
* </pre>
* <p>
* The rule can be declared as static so that it only has to check once for all tests in the enclosing test case, but
* there isn't a lot of overhead in making it non-static.
* </p>
*
* @see Assume
* @see AssumptionViolatedException
*
* @author Dave Syer
*
*/
public class ServerRunning implements MethodRule, RestTemplateHolder {
private static Log logger = LogFactory.getLog(ServerRunning.class);
// Static so that we only test once on failure: speeds up test suite
private static Map<Integer, Boolean> serverOnline = new HashMap<Integer, Boolean>();
// Static so that we only test once on failure
private static Map<Integer, Boolean> serverOffline = new HashMap<Integer, Boolean>();
private final boolean assumeOnline;
private static int DEFAULT_PORT = 8080;
private static String DEFAULT_HOST = "localhost";
private int port;
private String hostName = DEFAULT_HOST;
private RestOperations client;
/**
* @return a new rule that assumes an existing running broker
*/
public static ServerRunning isRunning() {
return new ServerRunning(true);
}
/**
* @return a new rule that assumes there is no existing broker
*/
public static ServerRunning isNotRunning() {
return new ServerRunning(false);
}
private ServerRunning(boolean assumeOnline) {
this.assumeOnline = assumeOnline;
setPort(DEFAULT_PORT);
}
/**
* @param port the port to set
*/
public void setPort(int port) {
this.port = port;
if (!serverOffline.containsKey(port)) {
serverOffline.put(port, true);
}
if (!serverOnline.containsKey(port)) {
serverOnline.put(port, true);
}
client = createRestTemplate();
}
/**
* @param hostName the hostName to set
*/
public void setHostName(String hostName) {
this.hostName = hostName;
}
public Statement apply(final Statement base, FrameworkMethod method, Object target) {
// Check at the beginning, so this can be used as a static field
if (assumeOnline) {
Assume.assumeTrue(serverOnline.get(port));
}
else {
Assume.assumeTrue(serverOffline.get(port));
}
RestTemplate client = new RestTemplate();
boolean followRedirects = HttpURLConnection.getFollowRedirects();
HttpURLConnection.setFollowRedirects(false);
boolean online = false;
try {
client.getForEntity(new UriTemplate(getUrl("/sparklr2/login.jsp")).toString(), String.class);
online = true;
logger.info("Basic connectivity test passed");
}
catch (RestClientException e) {
logger.warn(String.format(
"Not executing tests because basic connectivity test failed for hostName=%s, port=%d", hostName,
port), e);
if (assumeOnline) {
Assume.assumeNoException(e);
}
}
finally {
HttpURLConnection.setFollowRedirects(followRedirects);
if (online) {
serverOffline.put(port, false);
if (!assumeOnline) {
Assume.assumeTrue(serverOffline.get(port));
}
}
else {
serverOnline.put(port, false);
}
}
final RestOperations savedClient = getRestTemplate();
postForStatus(savedClient, "/sparklr2/oauth/uncache_approvals",
new LinkedMultiValueMap<String, String>());
return new Statement() {
@Override
public void evaluate() throws Throwable {
try {
base.evaluate();
}
finally {
postForStatus(savedClient, "/sparklr2/oauth/cache_approvals",
new LinkedMultiValueMap<String, String>());
}
}
};
}
public String getBaseUrl() {
return "http://" + hostName + ":" + port;
}
public String getUrl(String path) {
if (path.startsWith("http")) {
return path;
}
if (!path.startsWith("/")) {
path = "/" + path;
}
return "http://" + hostName + ":" + port + path;
}
public ResponseEntity<String> postForString(String path, MultiValueMap<String, String> formData) {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
return client.exchange(getUrl(path), HttpMethod.POST, new HttpEntity<MultiValueMap<String, String>>(formData,
headers), String.class);
}
public ResponseEntity<String> postForString(String path, HttpHeaders headers, MultiValueMap<String, String> formData) {
HttpHeaders actualHeaders = new HttpHeaders();
actualHeaders.putAll(headers);
actualHeaders.setAccept(Arrays.asList(MediaType.APPLICATION_FORM_URLENCODED));
return client.exchange(getUrl(path), HttpMethod.POST, new HttpEntity<MultiValueMap<String, String>>(formData,
actualHeaders), String.class);
}
@SuppressWarnings("rawtypes")
public ResponseEntity<Map> postForMap(String path, MultiValueMap<String, String> formData) {
return postForMap(path, new HttpHeaders(), formData);
}
@SuppressWarnings("rawtypes")
public ResponseEntity<Map> postForMap(String path, HttpHeaders headers, MultiValueMap<String, String> formData) {
if (headers.getContentType() == null) {
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
}
return client.exchange(getUrl(path), HttpMethod.POST, new HttpEntity<MultiValueMap<String, String>>(formData,
headers), Map.class);
}
public ResponseEntity<Void> postForStatus(String path, MultiValueMap<String, String> formData) {
return postForStatus(this.client, path, formData);
}
public ResponseEntity<Void> postForStatus(String path, HttpHeaders headers, MultiValueMap<String, String> formData) {
return postForStatus(this.client, path, headers, formData);
}
private ResponseEntity<Void> postForStatus(RestOperations client, String path,
MultiValueMap<String, String> formData) {
return postForStatus(client, path, new HttpHeaders(), formData);
}
private ResponseEntity<Void> postForStatus(RestOperations client, String path, HttpHeaders headers,
MultiValueMap<String, String> formData) {
HttpHeaders actualHeaders = new HttpHeaders();
actualHeaders.putAll(headers);
actualHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
return client.exchange(getUrl(path), HttpMethod.POST, new HttpEntity<MultiValueMap<String, String>>(formData,
actualHeaders), null);
}
public ResponseEntity<Void> postForRedirect(String path, HttpHeaders headers, MultiValueMap<String, String> params) {
ResponseEntity<Void> exchange = postForStatus(path, headers, params);
if (exchange.getStatusCode() != HttpStatus.FOUND) {
throw new IllegalStateException("Expected 302 but server returned status code " + exchange.getStatusCode());
}
if (exchange.getHeaders().containsKey("Set-Cookie")) {
String cookie = exchange.getHeaders().getFirst("Set-Cookie");
headers.set("Cookie", cookie);
}
String location = exchange.getHeaders().getLocation().toString();
return client.exchange(location, HttpMethod.GET, new HttpEntity<Void>(null, headers), null);
}
public ResponseEntity<String> getForString(String path) {
return getForString(path, new HttpHeaders());
}
public ResponseEntity<String> getForString(String path, final HttpHeaders headers) {
return client.exchange(getUrl(path), HttpMethod.GET, new HttpEntity<Void>((Void) null, headers), String.class);
}
public ResponseEntity<String> getForString(String path, final HttpHeaders headers, Map<String, String> uriVariables) {
return client.exchange(getUrl(path), HttpMethod.GET, new HttpEntity<Void>((Void) null, headers), String.class,
uriVariables);
}
public ResponseEntity<Void> getForResponse(String path, final HttpHeaders headers, Map<String, String> uriVariables) {
HttpEntity<Void> request = new HttpEntity<Void>(null, headers);
return client.exchange(getUrl(path), HttpMethod.GET, request, null, uriVariables);
}
public ResponseEntity<Void> getForResponse(String path, HttpHeaders headers) {
return getForResponse(path, headers, Collections.<String, String> emptyMap());
}
public HttpStatus getStatusCode(String path, final HttpHeaders headers) {
ResponseEntity<Void> response = getForResponse(path, headers);
return response.getStatusCode();
}
public HttpStatus getStatusCode(String path) {
return getStatusCode(getUrl(path), null);
}
public void setRestTemplate(RestOperations restTemplate) {
client = restTemplate;
}
public RestOperations getRestTemplate() {
return client;
}
public RestOperations createRestTemplate() {
RestTemplate client = new RestTemplate();
client.setRequestFactory(new HttpComponentsClientHttpRequestFactory() {
@Override
public HttpClient getHttpClient() {
HttpClient client = super.getHttpClient();
client.getParams().setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, false);
client.getParams().setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.IGNORE_COOKIES);
return client;
}
});
client.setErrorHandler(new ResponseErrorHandler() {
// Pass errors through in response entity for status code analysis
public boolean hasError(ClientHttpResponse response) throws IOException {
return false;
}
public void handleError(ClientHttpResponse response) throws IOException {
}
});
return client;
}
public UriBuilder buildUri(String url) {
return UriBuilder.fromUri(url.startsWith("http:") ? url : getUrl(url));
}
public static class UriBuilder {
private final String url;
private Map<String, String> params = new LinkedHashMap<String, String>();
public UriBuilder(String url) {
this.url = url;
}
public static UriBuilder fromUri(String url) {
return new UriBuilder(url);
}
public UriBuilder queryParam(String key, String value) {
params.put(key, value);
return this;
}
public String pattern() {
StringBuilder builder = new StringBuilder();
// try {
builder.append(url.replace(" ", "+"));
if (!params.isEmpty()) {
builder.append("?");
boolean first = true;
for (String key : params.keySet()) {
if (!first) {
builder.append("&");
}
else {
first = false;
}
String value = params.get(key);
if (value.contains("=")) {
value = value.replace("=", "%3D");
}
builder.append(key + "={" + key + "}");
}
}
return builder.toString();
}
public Map<String, String> params() {
return params;
}
public URI build() {
return new UriTemplate(pattern()).expand(params);
}
}
}
package org.springframework.security.oauth.examples.tonr;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Assume;
import org.junit.internal.AssumptionViolatedException;
import org.junit.rules.MethodRule;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.Statement;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RequestCallback;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.ResponseExtractor;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriTemplate;
import org.springframework.web.util.UriUtils;
/**
* <p>
* A rule that prevents integration tests from failing if the server application is not running or not accessible. If
* the server is not running in the background all the tests here will simply be skipped because of a violated
* assumption (showing as successful). Usage:
* </p>
*
* <pre>
* &#064;Rule public static BrokerRunning brokerIsRunning = BrokerRunning.isRunning();
*
* &#064;Test public void testSendAndReceive() throws Exception { // ... test using RabbitTemplate etc. }
* </pre>
* <p>
* The rule can be declared as static so that it only has to check once for all tests in the enclosing test case, but
* there isn't a lot of overhead in making it non-static.
* </p>
*
* @see Assume
* @see AssumptionViolatedException
*
* @author Dave Syer
*
*/
public class ServerRunning implements MethodRule {
private static Log logger = LogFactory.getLog(ServerRunning.class);
// Static so that we only test once on failure: speeds up test suite
private static Map<Integer, Boolean> serverOnline = new HashMap<Integer, Boolean>();
// Static so that we only test once on failure
private static Map<Integer, Boolean> serverOffline = new HashMap<Integer, Boolean>();
private final boolean assumeOnline;
private static int DEFAULT_PORT = 8080;
private static String DEFAULT_HOST = "localhost";
private int port;
private String hostName = DEFAULT_HOST;
private RestTemplate client;
/**
* @return a new rule that assumes an existing running broker
*/
public static ServerRunning isRunning() {
return new ServerRunning(true);
}
/**
* @return a new rule that assumes there is no existing broker
*/
public static ServerRunning isNotRunning() {
return new ServerRunning(false);
}
private ServerRunning(boolean assumeOnline) {
this.assumeOnline = assumeOnline;
setPort(DEFAULT_PORT);
}
/**
* @param port the port to set
*/
public void setPort(int port) {
this.port = port;
if (!serverOffline.containsKey(port)) {
serverOffline.put(port, true);
}
if (!serverOnline.containsKey(port)) {
serverOnline.put(port, true);
}
client = getRestTemplate();
}
/**
* @param hostName the hostName to set
*/
public void setHostName(String hostName) {
this.hostName = hostName;
}
public Statement apply(final Statement base, FrameworkMethod method, Object target) {
// Check at the beginning, so this can be used as a static field
if (assumeOnline) {
Assume.assumeTrue(serverOnline.get(port));
} else {
Assume.assumeTrue(serverOffline.get(port));
}
RestTemplate client = new RestTemplate();
boolean followRedirects = HttpURLConnection.getFollowRedirects();
HttpURLConnection.setFollowRedirects(false);
boolean online = false;
try {
client.getForEntity(new UriTemplate(getUrl("/sparklr2/login.jsp")).toString(), String.class);
online = true;
logger.info("Basic connectivity test passed");
} catch (RestClientException e) {
logger.warn(String.format(
"Not executing tests because basic connectivity test failed for hostName=%s, port=%d", hostName,
port), e);
if (assumeOnline) {
Assume.assumeNoException(e);
}
} finally {
HttpURLConnection.setFollowRedirects(followRedirects);
if (online) {
serverOffline.put(port, false);
if (!assumeOnline) {
Assume.assumeTrue(serverOffline.get(port));
}
} else {
serverOnline.put(port, false);
}
}
return new Statement() {
@Override
public void evaluate() throws Throwable {
try {
postForStatus("/sparklr2/oauth/uncache_approvals", new LinkedMultiValueMap<String, String>());
base.evaluate();
} finally {
postForStatus("/sparklr2/oauth/cache_approvals", new LinkedMultiValueMap<String, String>());
}
}
};
}
public String getBaseUrl() {
return "http://" + hostName + ":" + port;
}
public String getUrl(String path) {
if (path.startsWith("http:")) {
return path;
}
if (!path.startsWith("/")) {
path = "/" + path;
}
return "http://" + hostName + ":" + port + path;
}
public ResponseEntity<String> postForString(String path, MultiValueMap<String, String> formData) {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_FORM_URLENCODED));
return client.exchange(getUrl(path), HttpMethod.POST, new HttpEntity<MultiValueMap<String, String>>(formData,
headers), String.class);
}
public ResponseEntity<Void> postForStatus(String path, MultiValueMap<String, String> formData) {
return postForStatus(path, new HttpHeaders(), formData);
}
public ResponseEntity<Void> postForStatus(String path, HttpHeaders headers, MultiValueMap<String, String> formData) {
HttpHeaders actualHeaders = new HttpHeaders();
actualHeaders.putAll(headers);
actualHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
return client.exchange(getUrl(path), HttpMethod.POST, new HttpEntity<MultiValueMap<String, String>>(formData,
actualHeaders), null);
}
public HttpHeaders postForHeaders(String path, MultiValueMap<String, String> formData) {
return postForHeaders(path, formData, null);
}
public HttpHeaders postForHeaders(String path, MultiValueMap<String, String> formData, final HttpHeaders headers) {
RequestCallback requestCallback = new NullRequestCallback();
if (headers != null) {
requestCallback = new RequestCallback() {
public void doWithRequest(ClientHttpRequest request) throws IOException {
request.getHeaders().putAll(headers);
}
};
}
StringBuilder builder = new StringBuilder(getUrl(path));
if (!path.contains("?")) {
builder.append("?");
} else {
builder.append("&");
}
for (String key : formData.keySet()) {
for (String value : formData.get(key)) {
builder.append(key + "=" + value);
builder.append("&");
}
}
builder.deleteCharAt(builder.length() - 1);
return client.execute(builder.toString(), HttpMethod.POST, requestCallback,
new ResponseExtractor<HttpHeaders>() {
public HttpHeaders extractData(ClientHttpResponse response) throws IOException {
return response.getHeaders();
}
});
}
public ResponseEntity<String> postForString(String path, HttpHeaders headers, MultiValueMap<String, String> formData) {
HttpHeaders actualHeaders = new HttpHeaders();
actualHeaders.putAll(headers);
headers.setAccept(Arrays.asList(MediaType.APPLICATION_FORM_URLENCODED));
return client.exchange(getUrl(path), HttpMethod.POST, new HttpEntity<MultiValueMap<String, String>>(formData,
headers), String.class);
}
public ResponseEntity<String> getForString(String path, final HttpHeaders headers) {
return client.exchange(getUrl(path), HttpMethod.GET, new HttpEntity<Void>((Void) null, headers), String.class);
}
public ResponseEntity<String> getForString(String path) {
return getForString(path, new HttpHeaders());
}
public String getForRedirect(String path, final HttpHeaders headers) {
ResponseEntity<Void> response = client.exchange(getUrl(path), HttpMethod.GET, new HttpEntity<Void>((Void) null,
headers), Void.class);
URI location = response.getHeaders().getLocation();
try {
return URLDecoder.decode(location.toString(), "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException("Could not decode URL", e);
}
}
public HttpStatus getStatusCode(String path, final HttpHeaders headers) {
RequestCallback requestCallback = new NullRequestCallback();
if (headers != null) {
requestCallback = new RequestCallback() {
public void doWithRequest(ClientHttpRequest request) throws IOException {
request.getHeaders().putAll(headers);
}
};
}
return client.execute(getUrl(path), HttpMethod.GET, requestCallback,
new ResponseExtractor<ResponseEntity<Void>>() {
public ResponseEntity<Void> extractData(ClientHttpResponse response) throws IOException {
FileCopyUtils.copyToByteArray(response.getBody());
return new ResponseEntity<Void>(response.getStatusCode());
}
}).getStatusCode();
}
public HttpStatus getStatusCode(String path) {
return getStatusCode(getUrl(path), null);
}
public RestTemplate getRestTemplate() {
RestTemplate client = new RestTemplate();
client.setRequestFactory(new SimpleClientHttpRequestFactory() {
@Override
protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
super.prepareConnection(connection, httpMethod);
connection.setInstanceFollowRedirects(false);
}
});
client.setErrorHandler(new ResponseErrorHandler() {
// Pass errors through in response entity for status code analysis
public boolean hasError(ClientHttpResponse response) throws IOException {
return false;
}
public void handleError(ClientHttpResponse response) throws IOException {
}
});
return client;
}
public UriBuilder buildUri(String url) {
return UriBuilder.fromUri(url.startsWith("http:") ? url : getUrl(url));
}
private static final class NullRequestCallback implements RequestCallback {
public void doWithRequest(ClientHttpRequest request) throws IOException {
}
}
public static class UriBuilder {
private final String url;
private MultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>();
public UriBuilder(String url) {
this.url = url;
}
public static UriBuilder fromUri(String url) {
return new UriBuilder(url);
}
public UriBuilder queryParam(String key, String value) {
params.add(key, value);
return this;
}
public URI build() {
StringBuilder builder = new StringBuilder(url);
try {
if (!params.isEmpty()) {
builder.append("?");
boolean first = true;
for (String key : params.keySet()) {
if (!first) {
builder.append("&");
} else {
first = false;
}
for (String value : params.get(key)) {
builder.append(key + "=" + UriUtils.encodeQueryParam(value, "UTF-8"));
}
}
}
return new URI(builder.toString());
} catch (UnsupportedEncodingException ex) {
// should not happen, UTF-8 is always supported
throw new IllegalStateException(ex);
} catch (URISyntaxException ex) {
throw new IllegalArgumentException("Could not create URI from [" + builder + "]: " + ex, ex);
}
}
}
}
org.apache.commons.logging.simplelog.defaultlog=info
org.apache.commons.logging.simplelog.showdatetime=true
org.apache.commons.logging.simplelog.dateTimeFormat='sparklr2' HH:mm:ss.SSS
org.apache.commons.logging.simplelog.log.org.springframework.web=debug
org.apache.commons.logging.simplelog.log.org.springframework.security=debug
org.apache.commons.logging.simplelog.log.org.springframework.security.access.method.DelegatingMethodSecurityMetadataSource=info
org.apache.commons.logging.simplelog.defaultlog=info
org.apache.commons.logging.simplelog.showdatetime=true
org.apache.commons.logging.simplelog.dateTimeFormat='tonr2' HH:mm:ss.SSS
org.apache.commons.logging.simplelog.log.org.springframework.security=debug
#org.apache.commons.logging.simplelog.log.org.springframework.security.oauth=info
org.apache.commons.logging.simplelog.log.org.springframework.web=debug
<%@ taglib prefix="authz" uri="http://www.springframework.org/security/tags" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link href="<c:url value="/main.css"/>" rel="stylesheet" type="text/css"/>
<title>tonr</title>
</head>
<body>
<div id="container">
<ul id="mainlinks">
<li><a href="<c:url value="/index.jsp"/>">home</a></li>
<authz:authorize ifNotGranted="ROLE_USER">
<li><a href="<c:url value="/login.jsp"/>">login</a></li>
</authz:authorize>
<li><a href="<c:url value="/sparklr/photos"/>" class="selected">sparklr pics</a></li>
<li><a href="<c:url value="/facebook/info"/>">facebook friends</a></li>
</ul>
<div id="content">
<h1>Your Sparklr Photos</h1>
<ul id="picturelist">
<c:forEach var="sparklrPhotoId" items="${photoIds}">
<li><img src="<c:url value="/sparklr/photos/${sparklrPhotoId}"/>"/></li>
</c:forEach>
</ul>
</div>
</div>
</body>
</html>
sparklrPhotoListURL=http://localhost:8080/sparklr2/photos?format=xml
sparklrPhotoURLPattern=http://localhost:8080/sparklr2/photos/%s
sparklrTrustedMessageURL=http://localhost:8080/sparklr2/photos/trusted/message
accessTokenUri=http://localhost:8080/sparklr2/token
userAuthorizationUri=http://localhost:8080/sparklr2/authorize
<?xml version="1.0" encoding="UTF-8" ?>
<Module>
<ModulePrefs title="OAuth Contacts" scrolling="true">
<Require feature="opensocial-0.8" />
<Require feature="locked-domain"/>
<OAuth>
<Service name="google">
<Access url="${gae.application.url}/oauth/access_token" method="GET" />
<Request url="${gae.application.url}/oauth/request_token" method="GET" />
<Authorization url="${gae.application.url}/oauth/confirm_access?callbackURL=http://oauth.gmodules.com/gadgets/oauthcallback" />
</Service>
</OAuth>
</ModulePrefs>
<Content type="html">
<![CDATA[
<!-- shindig oauth popup handling code -->
<script src="http://gadget-doc-examples.googlecode.com/svn/trunk/opensocial-gadgets/popup.js"></script>
<style>
#main {
margin: 0px;
padding: 0px;
font-size: small;
}
</style>
<div id="main" style="display: none">
</div>
<div id="approval" style="display: none">
<img src="http://gadget-doc-examples.googlecode.com/svn/trunk/images/new.gif">
<a href="#" id="personalize">Personalize this gadget</a>
</div>
<div id="waiting" style="display: none">
Please click
<a href="#" id="approvaldone">I've approved access</a>
once you've approved access to your data.
</div>
<script type="text/javascript">
// Display UI depending on OAuth access state of the gadget (see <divs> above).
// If user hasn't approved access to data, provide a "Personalize this gadget" link
// that contains the oauthApprovalUrl returned from makeRequest.
//
// If the user has opened the popup window but hasn't yet approved access, display
// text prompting the user to confirm that s/he approved access to data. The user
// may not ever need to click this link, if the gadget is able to automatically
// detect when the user has approved access, but showing the link gives users
// an option to fetch their data even if the automatic detection fails.
//
// When the user confirms access, the fetchData() function is invoked again to
// obtain and display the user's data.
function showOneSection(toshow) {
var sections = [ 'main', 'approval', 'waiting' ];
for (var i=0; i < sections.length; ++i) {
var s = sections[i];
var el = document.getElementById(s);
if (s === toshow) {
el.style.display = "block";
} else {
el.style.display = "none";
}
}
}
// Process returned JSON feed to display data.
function showResults(result) {
showOneSection('main');
var titleElement = document.createElement('div');
var nameNode = document.createTextNode("some photos");
titleElement.appendChild(nameNode);
document.getElementById("main").appendChild(titleElement);
document.getElementById("main").appendChild(document.createElement("br"));
list = result.photos;
for(var i = 0; i < list.length; i++) {
entry = list[i];
var divElement = document.createElement('div');
divElement.setAttribute('class', 'name');
var valueNode = document.createTextNode(entry.name);
divElement.appendChild(nameNode);
divElement.appendChild(valueNode);
document.getElementById("main").appendChild(divElement);
}
}
// Invoke makeRequest() to fetch data from the service provider endpoint.
// Depending on the results of makeRequest, decide which version of the UI
// to ask showOneSection() to display. If user has approved access to his
// or her data, display data.
// If the user hasn't approved access yet, response.oauthApprovalUrl contains a
// URL that includes a Google-supplied request token. This is presented in the
// gadget as a link that the user clicks to begin the approval process.
function fetchData() {
var params = {};
url = "${gae.application.url}/json/photos";
params[gadgets.io.RequestParameters.CONTENT_TYPE] = gadgets.io.ContentType.JSON;
params[gadgets.io.RequestParameters.AUTHORIZATION] = gadgets.io.AuthorizationType.OAUTH;
params[gadgets.io.RequestParameters.OAUTH_SERVICE_NAME] = "google";
params[gadgets.io.RequestParameters.OAUTH_USE_TOKEN] = "always";
params[gadgets.io.RequestParameters.METHOD] = gadgets.io.MethodType.GET;
gadgets.io.makeRequest(url, function (response) {
if (response.oauthApprovalUrl) {
// Create the popup handler. The onOpen function is called when the user
// opens the popup window. The onClose function is called when the popup
// window is closed.
var popup = shindig.oauth.popup({
destination: response.oauthApprovalUrl,
windowOptions: null,
onOpen: function() { showOneSection('waiting'); },
onClose: function() { fetchData(); }
});
// Use the popup handler to attach onclick handlers to UI elements. The
// createOpenerOnClick() function returns an onclick handler to open the
// popup window. The createApprovedOnClick function returns an onclick
// handler that will close the popup window and attempt to fetch the user's
// data again.
var personalize = document.getElementById('personalize');
personalize.onclick = popup.createOpenerOnClick();
var approvaldone = document.getElementById('approvaldone');
approvaldone.onclick = popup.createApprovedOnClick();
showOneSection('approval');
} else if (response.data) {
showOneSection('main');
showResults(response.data);
} else {
// The response.oauthError and response.oauthErrorText values may help debug
// problems with your gadget.
var main = document.getElementById('main');
var err = document.createTextNode('OAuth error: ' +
response.oauthError + ': ' + response.oauthErrorText);
main.appendChild(err);
showOneSection('main');
}
}, params);
}
// Call fetchData() when gadget loads.
gadgets.util.registerOnLoadHandler(fetchData);
</script>
]]>
</Content>
</Module>
package org.springframework.security.oauth.examples.tonr.mvc;
import java.awt.image.BufferedImage;
import java.io.InputStream;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.MemoryCacheImageInputStream;
import javax.servlet.UnavailableException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.security.oauth.examples.tonr.SparklrService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author Ryan Heaton
* @author Dave Syer
*/
@Controller
public class SparklrController {
private SparklrService sparklrService;
@RequestMapping("/sparklr/photos")
public String photos(Model model) throws Exception {
model.addAttribute("photoIds", sparklrService.getSparklrPhotoIds());
return "sparklr";
}
@RequestMapping("/sparklr/photos/{id}")
public ResponseEntity<BufferedImage> photo(@PathVariable String id) throws Exception {
InputStream photo = sparklrService.loadSparklrPhoto(id);
if (photo == null) {
throw new UnavailableException("The requested photo does not exist");
}
BufferedImage body;
MediaType contentType = MediaType.IMAGE_JPEG;
Iterator<ImageReader> imageReaders = ImageIO.getImageReadersByMIMEType(contentType.toString());
if (imageReaders.hasNext()) {
ImageReader imageReader = imageReaders.next();
ImageReadParam irp = imageReader.getDefaultReadParam();
imageReader.setInput(new MemoryCacheImageInputStream(photo), true);
body = imageReader.read(0, irp);
} else {
throw new HttpMessageNotReadableException("Could not find javax.imageio.ImageReader for Content-Type ["
+ contentType + "]");
}
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_JPEG);
return new ResponseEntity<BufferedImage>(body, headers, HttpStatus.OK);
}
@RequestMapping("/trusted/message")
public String trusted(Model model) throws Exception {
model.addAttribute("message", this.sparklrService.getTrustedMessage());
return "home";
}
public void setSparklrService(SparklrService sparklrService) {
this.sparklrService = sparklrService;
}
}
package org.springframework.security.oauth.examples.tonr;
/**
* @author Ryan Heaton
*/
public class SparklrException extends Exception {
public SparklrException(String message) {
super(message);
}
}
package org.springframework.security.oauth.examples.tonr;
import java.io.InputStream;
import java.util.List;
/**
* @author Ryan Heaton
*/
public interface SparklrService {
/**
* Get the list of Sparklr photo ids for the current user.
*
* @return The list of photo ids for the current user.
*/
List<String> getSparklrPhotoIds() throws SparklrException;
/**
* Loads the Sparklr photo for the current user.
*
* @param id the id or the photo.
* @return The sparklr photo.
*/
InputStream loadSparklrPhoto(String id) throws SparklrException;
/**
* @return a message
*/
String getTrustedMessage();
}
package org.springframework.security.oauth.examples.tonr.impl;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.springframework.security.oauth.examples.tonr.SparklrException;
import org.springframework.security.oauth.examples.tonr.SparklrService;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.web.client.RestOperations;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* @author Ryan Heaton
*/
public class SparklrServiceImpl implements SparklrService {
private String sparklrPhotoListURL;
private String sparklrTrustedMessageURL;
private String sparklrPhotoURLPattern;
private RestOperations sparklrRestTemplate;
private RestOperations trustedClientRestTemplate;
public List<String> getSparklrPhotoIds() throws SparklrException {
try {
InputStream photosXML = new ByteArrayInputStream(sparklrRestTemplate.getForObject(
URI.create(sparklrPhotoListURL), byte[].class));
final List<String> photoIds = new ArrayList<String>();
SAXParserFactory parserFactory = SAXParserFactory.newInstance();
parserFactory.setValidating(false);
parserFactory.setXIncludeAware(false);
parserFactory.setNamespaceAware(false);
SAXParser parser = parserFactory.newSAXParser();
parser.parse(photosXML, new DefaultHandler() {
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
if ("photo".equals(qName)) {
photoIds.add(attributes.getValue("id"));
}
}
});
return photoIds;
} catch (IOException e) {
throw new IllegalStateException(e);
} catch (SAXException e) {
throw new IllegalStateException(e);
} catch (ParserConfigurationException e) {
throw new IllegalStateException(e);
}
}
public InputStream loadSparklrPhoto(String id) throws SparklrException {
return new ByteArrayInputStream(sparklrRestTemplate.getForObject(
URI.create(String.format(sparklrPhotoURLPattern, id)), byte[].class));
}
public String getTrustedMessage() {
return this.trustedClientRestTemplate.getForObject(URI.create(sparklrTrustedMessageURL), String.class);
}
public void setSparklrPhotoURLPattern(String sparklrPhotoURLPattern) {
this.sparklrPhotoURLPattern = sparklrPhotoURLPattern;
}
public void setSparklrPhotoListURL(String sparklrPhotoListURL) {
this.sparklrPhotoListURL = sparklrPhotoListURL;
}
public void setSparklrTrustedMessageURL(String sparklrTrustedMessageURL) {
this.sparklrTrustedMessageURL = sparklrTrustedMessageURL;
}
public void setSparklrRestTemplate(OAuth2RestTemplate sparklrRestTemplate) {
this.sparklrRestTemplate = sparklrRestTemplate;
}
public void setTrustedClientRestTemplate(RestOperations trustedClientRestTemplate) {
this.trustedClientRestTemplate = trustedClientRestTemplate;
}
}
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.oauth.examples.sparklr.oauth;
import java.util.Collection;
import java.util.HashSet;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.provider.AuthorizationRequest;
import org.springframework.security.oauth2.provider.approval.TokenServicesUserApprovalHandler;
/**
* @author Dave Syer
*
*/
public class SparklrUserApprovalHandler extends TokenServicesUserApprovalHandler {
private Collection<String> autoApproveClients = new HashSet<String>();
private boolean useTokenServices = true;
/**
* @param useTokenServices the useTokenServices to set
*/
public void setUseTokenServices(boolean useTokenServices) {
this.useTokenServices = useTokenServices;
}
/**
* @param autoApproveClients the auto approve clients to set
*/
public void setAutoApproveClients(Collection<String> autoApproveClients) {
this.autoApproveClients = autoApproveClients;
}
/**
* Allows automatic approval for a white list of clients in the implicit grant case.
*
* @param authorizationRequest The authorization request.
* @param userAuthentication the current user authentication
*
* @return Whether the specified request has been approved by the current user.
*/
public boolean isApproved(AuthorizationRequest authorizationRequest, Authentication userAuthentication) {
if (useTokenServices && super.isApproved(authorizationRequest, userAuthentication)) {
return true;
}
if (!userAuthentication.isAuthenticated()) {
return false;
}
return authorizationRequest.isApproved()
|| (authorizationRequest.getResponseTypes().contains("token") && autoApproveClients
.contains(authorizationRequest.getClientId()));
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:oauth="http://www.springframework.org/schema/security/oauth2" xmlns:sec="http://www.springframework.org/schema/security"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-1.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<!-- Just for testing... -->
<http pattern="/oauth/cache_approvals" security="none" xmlns="http://www.springframework.org/schema/security" />
<http pattern="/oauth/uncache_approvals" security="none" xmlns="http://www.springframework.org/schema/security" />
<http pattern="/oauth/token" create-session="stateless" authentication-manager-ref="clientAuthenticationManager"
entry-point-ref="oauthAuthenticationEntryPoint" xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />
<anonymous enabled="false" />
<http-basic entry-point-ref="oauthAuthenticationEntryPoint" />
<!-- include this only if you need to authenticate clients via request parameters -->
<custom-filter ref="clientCredentialsTokenEndpointFilter" before="BASIC_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
<!-- The OAuth2 protected resources are separated out into their own block so we can deal with authorization and error handling
separately. This isn't mandatory, but it makes it easier to control the behaviour. -->
<http pattern="/oauth/(users|clients)/.*" request-matcher="regex" create-session="stateless" entry-point-ref="oauthAuthenticationEntryPoint"
use-expressions="true" xmlns="http://www.springframework.org/schema/security">
<anonymous enabled="false" />
<intercept-url pattern="/oauth/users/([^/].*?)/tokens/.*"
access="oauthClientHasRole('ROLE_CLIENT') and (hasRole('ROLE_USER') or oauthIsClient()) and oauthHasScope('write')"
method="DELETE" />
<intercept-url pattern="/oauth/users/.*"
access="oauthClientHasRole('ROLE_CLIENT') and (hasRole('ROLE_USER') or oauthIsClient()) and oauthHasScope('read')"
method="GET" />
<intercept-url pattern="/oauth/clients/.*" access="oauthClientHasRole('ROLE_CLIENT') and oauthIsClient() and oauthHasScope('read')"
method="GET" />
<custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
<expression-handler ref="oauthWebExpressionHandler" />
</http>
<!-- The OAuth2 protected resources are separated out into their own block so we can deal with authorization and error handling
separately. This isn't mandatory, but it makes it easier to control the behaviour. -->
<http pattern="/photos/**" create-session="never" entry-point-ref="oauthAuthenticationEntryPoint"
access-decision-manager-ref="accessDecisionManager" xmlns="http://www.springframework.org/schema/security">
<anonymous enabled="false" />
<intercept-url pattern="/photos" access="ROLE_USER,SCOPE_READ" />
<intercept-url pattern="/photos/trusted/**" access="ROLE_CLIENT,SCOPE_TRUST" />
<intercept-url pattern="/photos/user/**" access="ROLE_USER,SCOPE_TRUST" />
<intercept-url pattern="/photos/**" access="ROLE_USER,SCOPE_READ" />
<custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
<http access-denied-page="/login.jsp?authorization_error=true" disable-url-rewriting="true"
xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/oauth/**" access="ROLE_USER" />
<intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<form-login authentication-failure-url="/login.jsp?authentication_error=true" default-target-url="/index.jsp"
login-page="/login.jsp" login-processing-url="/login.do" />
<logout logout-success-url="/index.jsp" logout-url="/logout.do" />
<anonymous />
</http>
<bean id="oauthAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="sparklr2" />
</bean>
<bean id="oauthAccessDeniedHandler" class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" />
<bean id="clientCredentialsTokenEndpointFilter" class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<property name="authenticationManager" ref="clientAuthenticationManager" />
</bean>
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased" xmlns="http://www.springframework.org/schema/beans">
<constructor-arg>
<list>
<bean class="org.springframework.security.oauth2.provider.vote.ScopeVoter" />
<bean class="org.springframework.security.access.vote.RoleVoter" />
<bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
</list>
</constructor-arg>
</bean>
<authentication-manager id="clientAuthenticationManager" xmlns="http://www.springframework.org/schema/security">
<authentication-provider user-service-ref="clientDetailsUserService" />
</authentication-manager>
<authentication-manager alias="authenticationManager" xmlns="http://www.springframework.org/schema/security">
<authentication-provider>
<user-service>
<user name="marissa" password="koala" authorities="ROLE_USER" />
<user name="paul" password="emu" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
<bean id="clientDetailsUserService" class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="clientDetails" />
</bean>
<bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.InMemoryTokenStore" />
<bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<property name="tokenStore" ref="tokenStore" />
<property name="supportRefreshToken" value="true" />
</bean>
<bean id="userApprovalHandler" class="org.springframework.security.oauth.examples.sparklr.oauth.SparklrUserApprovalHandler">
<property name="autoApproveClients">
<set>
<value>my-less-trusted-autoapprove-client</value>
</set>
</property>
<property name="tokenServices" ref="tokenServices" />
</bean>
<oauth:authorization-server client-details-service-ref="clientDetails" token-services-ref="tokenServices"
user-approval-handler-ref="userApprovalHandler" token-endpoint-url="/token" authorization-endpoint-url="/authorize">
<oauth:authorization-code />
<oauth:implicit />
<oauth:refresh-token />
<oauth:client-credentials />
<oauth:password />
</oauth:authorization-server>
<oauth:resource-server id="resourceServerFilter" resource-id="sparklr" token-services-ref="tokenServices" />
<oauth:client-details-service id="clientDetails">
<oauth:client client-id="my-trusted-client" authorized-grant-types="password,authorization_code,refresh_token,implicit"
authorities="ROLE_CLIENT, ROLE_TRUSTED_CLIENT" scope="read,write,trust" />
<oauth:client client-id="my-trusted-client-with-secret" authorized-grant-types="password,authorization_code,refresh_token,implicit"
secret="somesecret" authorities="ROLE_CLIENT, ROLE_TRUSTED_CLIENT" />
<oauth:client client-id="my-less-trusted-client" authorized-grant-types="authorization_code,implicit"
authorities="ROLE_CLIENT" />
<oauth:client client-id="my-less-trusted-autoapprove-client" authorized-grant-types="implicit"
authorities="ROLE_CLIENT" />
<oauth:client client-id="my-client-with-registered-redirect" authorized-grant-types="authorization_code,client_credentials"
authorities="ROLE_CLIENT" redirect-uri="http://anywhere?key=value" scope="read,trust" />
<oauth:client client-id="my-untrusted-client-with-registered-redirect" authorized-grant-types="authorization_code"
authorities="ROLE_CLIENT" redirect-uri="http://anywhere" scope="read" />
<oauth:client client-id="tonr" resource-ids="sparklr" authorized-grant-types="authorization_code,implicit"
authorities="ROLE_CLIENT" scope="read,write" secret="secret" />
</oauth:client-details-service>
<mvc:annotation-driven />
<mvc:default-servlet-handler />
<sec:global-method-security pre-post-annotations="enabled" proxy-target-class="true">
<!--you could also wire in the expression handler up at the layer of the http filters. See https://jira.springsource.org/browse/SEC-1452 -->
<sec:expression-handler ref="oauthExpressionHandler" />
</sec:global-method-security>
<oauth:expression-handler id="oauthExpressionHandler" />
<oauth:web-expression-handler id="oauthWebExpressionHandler" />
<!--Basic application beans. -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<bean id="photoController" class="org.springframework.security.oauth.examples.sparklr.mvc.PhotoController">
<property name="photoService" ref="photoServices" />
</bean>
<bean id="adminController" class="org.springframework.security.oauth.examples.sparklr.mvc.AdminController">
<property name="tokenServices" ref="tokenServices" />
<property name="userApprovalHandler" ref="userApprovalHandler" />
</bean>
<bean id="accessConfirmationController" class="org.springframework.security.oauth.examples.sparklr.mvc.AccessConfirmationController">
<property name="clientDetailsService" ref="clientDetails" />
</bean>
<bean id="photoServices" class="org.springframework.security.oauth.examples.sparklr.impl.PhotoServiceImpl">
<property name="photos">
<list>
<bean class="org.springframework.security.oauth.examples.sparklr.PhotoInfo">
<property name="id" value="1" />
<property name="name" value="photo1.jpg" />
<property name="userId" value="marissa" />
<property name="resourceURL" value="/org/springframework/security/oauth/examples/sparklr/impl/resources/photo1.jpg" />
</bean>
<bean class="org.springframework.security.oauth.examples.sparklr.PhotoInfo">
<property name="id" value="2" />
<property name="name" value="photo2.jpg" />
<property name="userId" value="paul" />
<property name="resourceURL" value="/org/springframework/security/oauth/examples/sparklr/impl/resources/photo2.jpg" />
</bean>
<bean class="org.springframework.security.oauth.examples.sparklr.PhotoInfo">
<property name="id" value="3" />
<property name="name" value="photo3.jpg" />
<property name="userId" value="marissa" />
<property name="resourceURL" value="/org/springframework/security/oauth/examples/sparklr/impl/resources/photo3.jpg" />
</bean>
<bean class="org.springframework.security.oauth.examples.sparklr.PhotoInfo">
<property name="id" value="4" />
<property name="name" value="photo4.jpg" />
<property name="userId" value="paul" />
<property name="resourceURL" value="/org/springframework/security/oauth/examples/sparklr/impl/resources/photo4.jpg" />
</bean>
<bean class="org.springframework.security.oauth.examples.sparklr.PhotoInfo">
<property name="id" value="5" />
<property name="name" value="photo5.jpg" />
<property name="userId" value="marissa" />
<property name="resourceURL" value="/org/springframework/security/oauth/examples/sparklr/impl/resources/photo5.jpg" />
</bean>
<bean class="org.springframework.security.oauth.examples.sparklr.PhotoInfo">
<property name="id" value="6" />
<property name="name" value="photo6.jpg" />
<property name="userId" value="paul" />
<property name="resourceURL" value="/org/springframework/security/oauth/examples/sparklr/impl/resources/photo6.jpg" />
</bean>
</list>
</property>
</bean>
</beans>
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:sec="http://www.springframework.org/schema/security"
xmlns:oauth="http://www.springframework.org/schema/security/oauth2" xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-1.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<http access-denied-page="/login.jsp?authorization_error=true" xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/sparklr/**" access="ROLE_USER" />
<intercept-url pattern="/facebook/**" access="ROLE_USER" />
<intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<form-login authentication-failure-url="/login.jsp?authentication_error=true" default-target-url="/index.jsp"
login-page="/login.jsp" login-processing-url="/login.do" />
<logout logout-success-url="/index.jsp" logout-url="/logout.do" />
<anonymous />
<custom-filter ref="oauth2ClientFilter" after="EXCEPTION_TRANSLATION_FILTER" />
</http>
<authentication-manager xmlns="http://www.springframework.org/schema/security">
<authentication-provider>
<user-service>
<user name="marissa" password="wombat" authorities="ROLE_USER" />
<user name="sam" password="kangaroo" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
<!--apply the oauth client context -->
<oauth:client id="oauth2ClientFilter" />
<!--define an oauth 2 resource for sparklr -->
<oauth:resource id="sparklr" type="authorization_code" client-id="tonr" client-secret="secret"
access-token-uri="${accessTokenUri}" user-authorization-uri="${userAuthorizationUri}" scope="read" />
<!--define an oauth 2 resource for trusted client on sparklr -->
<oauth:resource id="trusted" type="client_credentials" client-id="my-client-with-registered-redirect"
access-token-uri="${accessTokenUri}" scope="trust" />
<!--define an oauth 2 resource for facebook. according to the facebook docs, the 'client-id' is the App ID, and the 'client-secret'
is the App Secret -->
<oauth:resource id="facebook" type="authorization_code" client-id="233668646673605" client-secret="33b17e044ee6a4fa383f46ec6e28ea1d"
authentication-scheme="query" access-token-uri="https://graph.facebook.com/oauth/access_token" user-authorization-uri="https://www.facebook.com/dialog/oauth"
token-name="oauth_token" client-authentication-scheme="form" />
<context:property-placeholder location="classpath:/sparklr.properties" />
<mvc:default-servlet-handler />
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.BufferedImageHttpMessageConverter" />
</mvc:message-converters>
</mvc:annotation-driven>
<bean id="contentViewResolver" class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
</map>
</property>
<property name="defaultViews">
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
</property>
</bean>
<!--Basic application beans. -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<bean id="sparklrController" class="org.springframework.security.oauth.examples.tonr.mvc.SparklrController">
<property name="sparklrService" ref="sparklrService" />
</bean>
<bean id="facebookController" class="org.springframework.security.oauth.examples.tonr.mvc.FacebookController">
<property name="facebookRestTemplate">
<oauth:rest-template resource="facebook">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<bean class="org.springframework.http.MediaType">
<!--facebook sends its json as text/javascript for some reason -->
<constructor-arg value="text" />
<constructor-arg value="javascript" />
</bean>
<bean class="org.springframework.http.MediaType">
<constructor-arg value="application" />
<constructor-arg value="json" />
</bean>
</list>
</property>
</bean>
</list>
</property>
</oauth:rest-template>
</property>
</bean>
<bean id="sparklrService" class="org.springframework.security.oauth.examples.tonr.impl.SparklrServiceImpl">
<property name="sparklrPhotoListURL" value="${sparklrPhotoListURL}" />
<property name="sparklrTrustedMessageURL" value="${sparklrTrustedMessageURL}" />
<property name="sparklrPhotoURLPattern" value="${sparklrPhotoURLPattern}" />
<property name="sparklrRestTemplate">
<oauth:rest-template resource="sparklr" />
</property>
<property name="trustedClientRestTemplate">
<oauth:rest-template resource="trusted" />
</property>
</bean>
</beans>
/* CSS Document */
body {
color: white;
font-family: 'Trebuchet MS', Helvetica, sans-serif;
font-size: 12px;
margin: 0 auto;
width: 736px;
background: url( 'images/bg.gif' );
}
#content {
background: #3d3d3d;
width: 676px;
margin-top: 20px;
padding: 0 30px 25px 30px;
}
a {
color: lightblue;
text-decoration: none;
}
a:hover {
color: red;
text-decoration: none;
}
h1 {
background: url( 'images/header.jpg' );
height: 36px;
width: 721px;
margin: 0 0 1em 0;
padding-top: 80px;
padding-left: 15px;
font-size: 1.8em;
font-variant: small-caps;
}
h2 {
font-size: 1.2em;
margin-left: -10px;
padding-top: 20px;
font-weight: bold;
letter-spacing: .3px;
}
.error h2 {
color: red;
font-size: 1.2em;
padding-top: 20px;
font-weight: bold;
letter-spacing: .3px;
}
.error p {
color: red;
}
p {
letter-spacing: .2px;
}
label {
text-indent: 20px;
letter-spacing: .2px;
padding: 5px 5px 5px 5px;
}
#footer {
font-size: .8em;
margin-top: 1em;
}
#footer a {
color: #333333;
font-weight: bold;
font-size: 1em
}
#footer a:hover {
color: red;
font-weight: bold;
font-size: 1em
}
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link href="main.css" rel="stylesheet" type="text/css"/>
<title>xgallery</title>
</head>
<body>
<div id="container">
<ul id="mainlinks">
<li><a href="#">home</a></li>
<li><a href="#">about</a></li>
<li><a href="#" class="selected">gallery pics</a></li>
<li><a href="http://www.naturaldesigngroup.co.uk">ndg</a></li>
<li><a href="http://www.planetphotoshop.com">planetphotoshop</a></li>
</ul>
<div id="content">
<ul id="picturelist">
<li>a tree<a href="#"><img src="images/autumntree.jpg" alt="a tree"/></a></li>
<li>the sea<a href="#"><img src="images/bluesea.jpg" alt="the sea"/></a></li>
<li>the forest<a href="#"><img src="images/greenforest.jpg" alt="the forest"/></a></li>
<li>a bunch of orange flowers<a href="#"><img src="images/orangeflowers.jpg" alt="a bunch of orange flowers"/></a></li>
<li>a turtle in the sea<a href="#"><img src="images/turtleblue.jpg" alt="a turtle in the sea"/></a></li>
<li>a garden/jungle thing<a href="#"><img src="images/jungle.jpg" alt="a garden/jungle thing"/></a></li>
<li>an oryx antelope in the desert<a href="#"><img src="images/antelope.jpg" alt="an oryx antelope in the desert"/></a></li>
<li>mesas in the desert<a href="#"><img src="images/desert.jpg" alt="mesas in the desert"/><span class="main"><!--This theme is free for distriubtion, so long as link to openwebdesing.org and dubaiapartments.biz stay on the theme--> Courtesy <a
href="http://www.openwebdesign.org" target="_blank">Open
Web Design</a><a href="http://www.dubaiapartments.biz" target="_blank"><img src="spacer.gif" width="5" height="5" border="0"/></a>Thanks
to <a href="http://www.dubaiapartments.biz/" target="_blank">Dubai Hotels</a></span></a></li>
</ul>
</div>
</div>
</body>
</html>
package org.springframework.security.oauth2.provider;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.client.test.OAuth2ContextConfiguration;
import org.springframework.security.oauth2.client.test.OAuth2ContextSetup;
import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails;
import org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordResourceDetails;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
/**
* @author Dave Syer
*/
public class TestAdminEndpoints {
@Rule
public ServerRunning serverRunning = ServerRunning.isRunning();
@Rule
public OAuth2ContextSetup context = OAuth2ContextSetup.standard(serverRunning);
@Test
@OAuth2ContextConfiguration(ResourceOwnerReadOnly.class)
public void testListTokensByUser() throws Exception {
ResponseEntity<String> result = serverRunning.getForString("/sparklr2/oauth/users/marissa/tokens");
assertEquals(HttpStatus.OK, result.getStatusCode());
// System.err.println(result.getBody());
assertTrue(result.getBody().contains(context.getAccessToken().getValue()));
}
@Test
@OAuth2ContextConfiguration(ResourceOwnerWriteOnly.class)
public void testRevokeTokenByUser() throws Exception {
OAuth2AccessToken token = context.getAccessToken();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
HttpEntity<?> request = new HttpEntity<Void>(headers);
assertEquals(
HttpStatus.NO_CONTENT,
serverRunning
.getRestTemplate()
.exchange(serverRunning.getUrl("/sparklr2/oauth/users/{user}/tokens/{token}"),
HttpMethod.DELETE, request, Void.class, "marissa", token.getValue()).getStatusCode());
ResponseEntity<String> result = serverRunning.getForString("/sparklr2/oauth/users/marissa/tokens", headers);
assertEquals(HttpStatus.UNAUTHORIZED, result.getStatusCode());
assertTrue(result.getBody().contains("invalid_token"));
}
@Test
@OAuth2ContextConfiguration(ClientCredentialsReadOnly.class)
public void testClientListsTokensOfUser() throws Exception {
ResponseEntity<String> result = serverRunning.getForString("/sparklr2/oauth/users/marissa/tokens");
assertEquals(HttpStatus.OK, result.getStatusCode());
assertTrue(result.getBody().startsWith("["));
assertTrue(result.getBody().endsWith("]"));
assertTrue(result.getBody().length() > 0);
}
@Test
@OAuth2ContextConfiguration(ResourceOwnerReadOnly.class)
public void testCannotListTokensOfAnotherUser() throws Exception {
assertEquals(HttpStatus.FORBIDDEN, serverRunning.getStatusCode("/sparklr2/oauth/users/foo/tokens"));
}
@Test
@OAuth2ContextConfiguration(ClientCredentialsReadOnly.class)
public void testListTokensByClient() throws Exception {
ResponseEntity<String> result = serverRunning
.getForString("/sparklr2/oauth/clients/my-client-with-registered-redirect/tokens");
assertEquals(HttpStatus.OK, result.getStatusCode());
assertTrue(result.getBody().contains(context.getAccessToken().getValue()));
}
@Test
@OAuth2ContextConfiguration(ResourceOwnerReadOnly.class)
public void testUserCannotListTokensOfClient() throws Exception {
assertEquals(HttpStatus.FORBIDDEN,
serverRunning.getStatusCode("/sparklr2/oauth/clients/my-client-with-registered-redirect/tokens"));
}
static class ResourceOwnerReadOnly extends ResourceOwnerPasswordResourceDetails {
public ResourceOwnerReadOnly(Object target) {
setClientId("my-trusted-client");
setId(getClientId());
setScope(Arrays.asList("read"));
setUsername("marissa");
setPassword("koala");
TestAdminEndpoints test = (TestAdminEndpoints) target;
setAccessTokenUri(test.serverRunning.getUrl("/sparklr2/oauth/token"));
}
}
static class ClientCredentialsReadOnly extends ClientCredentialsResourceDetails {
public ClientCredentialsReadOnly(Object target) {
setClientId("my-client-with-registered-redirect");
setId(getClientId());
setScope(Arrays.asList("read"));
TestAdminEndpoints test = (TestAdminEndpoints) target;
setAccessTokenUri(test.serverRunning.getUrl("/sparklr2/oauth/token"));
}
}
static class ResourceOwnerWriteOnly extends ResourceOwnerReadOnly {
public ResourceOwnerWriteOnly(Object target) {
super(target);
setScope(Arrays.asList("write"));
}
}
}
package org.springframework.security.oauth.examples.tonr;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.Arrays;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.UserRedirectRequiredException;
import org.springframework.security.oauth2.client.token.DefaultAccessTokenRequest;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
/**
* @author Ryan Heaton
* @author Dave Syer
*/
public class TestAuthorizationCodeGrant {
@Rule
public ServerRunning serverRunning = ServerRunning.isRunning();
private AuthorizationCodeResourceDetails resource = new AuthorizationCodeResourceDetails();
{
resource.setAccessTokenUri(serverRunning.getUrl("/sparklr2/oauth/token"));
resource.setClientId("my-client-with-registered-redirect");
resource.setId("sparklr");
resource.setScope(Arrays.asList("trust"));
resource.setUserAuthorizationUri(serverRunning.getUrl("/sparklr2/oauth/authorize"));
}
@Test
public void testCannotConnectWithoutToken() throws Exception {
OAuth2RestTemplate template = new OAuth2RestTemplate(resource);
resource.setPreEstablishedRedirectUri("http://anywhere.com");
try {
template.getForObject(serverRunning.getUrl("/tonr2/photos"), String.class);
fail("Expected UserRedirectRequiredException");
}
catch (UserRedirectRequiredException e) {
String message = e.getMessage();
assertTrue("Wrong message: " + message,
message.contains("A redirect is required to get the users approval"));
}
}
@Test
public void testAttemptedTokenAcquisitionWithNoRedirect() throws Exception {
AuthorizationCodeAccessTokenProvider provider = new AuthorizationCodeAccessTokenProvider();
try {
OAuth2AccessToken token = provider.obtainAccessToken(resource, new DefaultAccessTokenRequest());
fail("Expected UserRedirectRequiredException");
assertNotNull(token);
}
catch (IllegalStateException e) {
String message = e.getMessage();
assertTrue("Wrong message: " + message, message.contains("No redirect URI has been established"));
}
}
@Test
public void testTokenAcquisitionWithCorrectContext() throws Exception {
MultiValueMap<String, String> form = new LinkedMultiValueMap<String, String>();
form.add("j_username", "marissa");
form.add("j_password", "wombat");
HttpHeaders response = serverRunning.postForHeaders("/tonr2/login.do", form);
String cookie = response.getFirst("Set-Cookie");
HttpHeaders headers = new HttpHeaders();
headers.set("Cookie", cookie);
// headers.setAccept(Collections.singletonList(MediaType.ALL));
headers.setAccept(MediaType.parseMediaTypes("image/png,image/*;q=0.8,*/*;q=0.5"));
String location = serverRunning.getForRedirect("/tonr2/sparklr/photos/1", headers);
location = authenticateAndApprove(location);
assertTrue("Redirect location should be to the original photo URL: " + location, location.contains("photos/1"));
HttpStatus status = serverRunning.getStatusCode(location, headers);
assertEquals(HttpStatus.OK, status);
}
private String authenticateAndApprove(String location) {
// First authenticate and grab the cookie
MultiValueMap<String, String> form = new LinkedMultiValueMap<String, String>();
form.add("j_username", "marissa");
form.add("j_password", "koala");
HttpHeaders response = serverRunning.postForHeaders("/sparklr2/login.do", form);
String cookie = response.getFirst("Set-Cookie");
HttpHeaders headers = new HttpHeaders();
headers.set("Cookie", cookie);
serverRunning.getForString(location, headers);
// Should be on user approval page now
form = new LinkedMultiValueMap<String, String>();
form.add("user_oauth_approval", "true");
response = serverRunning.postForHeaders("/sparklr2/oauth/authorize", form, headers);
return response.getLocation().toString();
}
}
/*
* Copyright 2006-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.springframework.security.oauth2.provider;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.util.Arrays;
import java.util.Map;
import java.util.StringTokenizer;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.security.oauth2.client.UserApprovalRequiredException;
import org.springframework.security.oauth2.client.UserRedirectRequiredException;
import org.springframework.security.oauth2.client.test.BeforeOAuth2Context;
import org.springframework.security.oauth2.client.test.OAuth2ContextConfiguration;
import org.springframework.security.oauth2.client.test.OAuth2ContextSetup;
import org.springframework.security.oauth2.client.token.AccessTokenRequest;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.RedirectMismatchException;
import org.springframework.security.oauth2.provider.ServerRunning.UriBuilder;
import org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.ResponseExtractor;
/**
* @author Dave Syer
* @author Luke Taylor
*/
public class TestAuthorizationCodeProvider {
@Rule
public ServerRunning serverRunning = ServerRunning.isRunning();
@Rule
public OAuth2ContextSetup context = OAuth2ContextSetup.standard(serverRunning);
private AuthorizationCodeAccessTokenProvider accessTokenProvider;
private String cookie;
private ClientHttpResponse tokenEndpointResponse;
@BeforeOAuth2Context
public void setupAccessTokenProvider() {
accessTokenProvider = new AuthorizationCodeAccessTokenProvider() {
private ResponseExtractor<OAuth2AccessToken> extractor = super.getResponseExtractor();
private ResponseExtractor<ResponseEntity<Void>> authExtractor = super.getAuthorizationResponseExtractor();
private ResponseErrorHandler errorHandler = super.getResponseErrorHandler();
@Override
protected ResponseErrorHandler getResponseErrorHandler() {
return new DefaultResponseErrorHandler() {
public void handleError(ClientHttpResponse response) throws IOException {
response.getHeaders();
response.getStatusCode();
tokenEndpointResponse = response;
errorHandler.handleError(response);
}
};
}
@Override
protected ResponseExtractor<OAuth2AccessToken> getResponseExtractor() {
return new ResponseExtractor<OAuth2AccessToken>() {
public OAuth2AccessToken extractData(ClientHttpResponse response) throws IOException {
response.getHeaders();
response.getStatusCode();
tokenEndpointResponse = response;
return extractor.extractData(response);
}
};
}
@Override
protected ResponseExtractor<ResponseEntity<Void>> getAuthorizationResponseExtractor() {
return new ResponseExtractor<ResponseEntity<Void>>() {
public ResponseEntity<Void> extractData(ClientHttpResponse response) throws IOException {
response.getHeaders();
response.getStatusCode();
tokenEndpointResponse = response;
return authExtractor.extractData(response);
}
};
}
};
context.setAccessTokenProvider(accessTokenProvider);
}
@BeforeOAuth2Context
public void loginAndExtractCookie() {
MultiValueMap<String, String> formData;
formData = new LinkedMultiValueMap<String, String>();
formData.add("j_username", "marissa");
formData.add("j_password", "koala");
String location = "/sparklr2/login.do";
ResponseEntity<Void> result = serverRunning.postForStatus(location, formData);
assertEquals(HttpStatus.FOUND, result.getStatusCode());
String cookie = result.getHeaders().getFirst("Set-Cookie");
assertNotNull("Expected cookie in " + result.getHeaders(), cookie);
this.cookie = cookie;
}
@Test
public void testResourceIsProtected() throws Exception {
// first make sure the resource is actually protected.
assertEquals(HttpStatus.UNAUTHORIZED, serverRunning.getStatusCode("/sparklr2/photos?format=json"));
}
@Test
@OAuth2ContextConfiguration(resource = MyLessTrustedClient.class, initialize = false)
public void testUnauthenticatedAuthorizationRequestRedirectsToLogin() throws Exception {
AccessTokenRequest request = context.getAccessTokenRequest();
request.setCurrentUri("http://anywhere");
request.add(AuthorizationEndpoint.USER_OAUTH_APPROVAL, "true");
String location = null;
try {
String code = accessTokenProvider.obtainAuthorizationCode(context.getResource(), request);
assertNotNull(code);
fail("Expected UserRedirectRequiredException");
}
catch (UserRedirectRequiredException e) {
location = e.getRedirectUri();
}
assertNotNull(location);
assertEquals(serverRunning.getUrl("/sparklr2/login.jsp"), location);
}
@Test
@OAuth2ContextConfiguration(resource = MyLessTrustedClient.class, initialize = false)
public void testSuccessfulAuthorizationCodeFlow() throws Exception {
// Once the request is ready and approved, we can continue with the access token
approveAccessTokenGrant("http://anywhere", true);
// Finally everything is in place for the grant to happen...
assertNotNull(context.getAccessToken());
AccessTokenRequest request = context.getAccessTokenRequest();
assertNotNull(request.getAuthorizationCode());
assertEquals(HttpStatus.OK, serverRunning.getStatusCode("/sparklr2/photos?format=json"));
}
@Test
@OAuth2ContextConfiguration(resource = MyLessTrustedClient.class, initialize = false)
public void testWrongRedirectUri() throws Exception {
approveAccessTokenGrant("http://anywhere", true);
AccessTokenRequest request = context.getAccessTokenRequest();
// The redirect is stored in the preserved state...
context.getOAuth2ClientContext().setPreservedState(request.getStateKey(), "http://nowhere");
// Finally everything is in place for the grant to happen...
try {
assertNotNull(context.getAccessToken());
fail("Expected RedirectMismatchException");
}
catch (RedirectMismatchException e) {
// expected
}
assertEquals(HttpStatus.BAD_REQUEST, tokenEndpointResponse.getStatusCode());
}
@Test
@OAuth2ContextConfiguration(resource = MyLessTrustedClient.class, initialize = false)
public void testUserDeniesConfirmation() throws Exception {
approveAccessTokenGrant("http://anywhere", false);
String location = null;
try {
assertNotNull(context.getAccessToken());
fail("Expected UserRedirectRequiredException");
}
catch (UserRedirectRequiredException e) {
location = e.getRedirectUri();
}
assertTrue("Wrong location: " + location, location.contains("state="));
assertTrue(location.startsWith("http://anywhere"));
assertTrue(location.substring(location.indexOf('?')).contains("error=access_denied"));
// It was a redirect that triggered our client redirect exception:
assertEquals(HttpStatus.FOUND, tokenEndpointResponse.getStatusCode());
}
@Test
public void testNoClientIdProvided() throws Exception {
ResponseEntity<Void> response = attemptToGetConfirmationPage(null, "http://anywhere");
// With no client id you get an InvalidClientException on the server which is redirected to /login
// TODO: make a better fist of alerting the user or server admin that there was a problem
assertEquals(HttpStatus.FOUND, response.getStatusCode());
assertTrue(response.getHeaders().getLocation().toString().contains("login.jsp"));
}
@Test
public void testNoRedirect() throws Exception {
ResponseEntity<Void> response = attemptToGetConfirmationPage("my-less-trusted-client", null);
// With no redirect uri you get an UnapprovedClientAuthenticationException on the server which is redirected to
// /login
// TODO: make a better fist of alerting the user or server admin that there was a problem
assertEquals(HttpStatus.FOUND, response.getStatusCode());
assertTrue(response.getHeaders().getLocation().toString().contains("login.jsp"));
}
@Test
@OAuth2ContextConfiguration(resource = MyClientWithRegisteredRedirect.class, initialize = false)
public void testSuccessfulFlowWithRegisteredRedirect() throws Exception {
// Once the request is ready and approved, we can continue with the access token
approveAccessTokenGrant("http://anywhere?key=value", true);
// Finally everything is in place for the grant to happen...
assertNotNull(context.getAccessToken());
AccessTokenRequest request = context.getAccessTokenRequest();
assertNotNull(request.getAuthorizationCode());
assertEquals(HttpStatus.OK, serverRunning.getStatusCode("/sparklr2/photos?format=json"));
}
@Test
public void testInvalidScopeInTokenRequest() throws Exception {
// Need to use the client with a redirect because "my-less-trusted-client" has no registered scopes
String code = getAuthorizationCode("my-client-with-registered-redirect", "http://anywhere?key=value", "bogus");
confirmTokenRequestError("my-client-with-registered-redirect", "http://anywhere?key=value", code, "bogus",
HttpStatus.FORBIDDEN, "invalid_scope");
}
@Test
@OAuth2ContextConfiguration(resource = MyClientWithRegisteredRedirect.class, initialize = false)
public void testInvalidScopeInResourceRequest() throws Exception {
AuthorizationCodeResourceDetails resource = (AuthorizationCodeResourceDetails) context.getResource();
resource.setScope(Arrays.asList("trust"));
approveAccessTokenGrant("http://anywhere?key=value", true);
assertNotNull(context.getAccessToken());
ResponseEntity<String> response = serverRunning.getForString("/sparklr2/photos?format=json");
assertEquals(HttpStatus.FORBIDDEN, response.getStatusCode());
String authenticate = response.getHeaders().getFirst("WWW-Authenticate");
assertNotNull(authenticate);
assertTrue(authenticate.startsWith("Bearer"));
assertTrue("Wrong header: " + authenticate, authenticate.contains("scope=\""));
}
@Test
public void testInvalidAccessToken() throws Exception {
// now make sure an unauthorized request fails the right way.
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", String.format("%s %s", OAuth2AccessToken.BEARER_TYPE, "FOO"));
ResponseEntity<String> response = serverRunning.getForString("/sparklr2/photos?format=json", headers);
assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode());
String authenticate = response.getHeaders().getFirst("WWW-Authenticate");
assertNotNull(authenticate);
assertTrue(authenticate.startsWith("Bearer"));
// Resource Server doesn't know what scopes are required until teh token can be validated
assertFalse(authenticate.contains("scope=\""));
}
@Test
@OAuth2ContextConfiguration(resource = MyClientWithRegisteredRedirect.class, initialize = false)
public void testRegisteredRedirectWithWrongRequestedRedirect() throws Exception {
try {
approveAccessTokenGrant("http://nowhere", true);
fail("Expected RedirectMismatchException");
}
catch (RedirectMismatchException e) {
}
assertEquals(HttpStatus.BAD_REQUEST, tokenEndpointResponse.getStatusCode());
}
@Test
@OAuth2ContextConfiguration(resource = MyClientWithRegisteredRedirect.class, initialize = false)
public void testRegisteredRedirectWithWrongOneInTokenEndpoint() throws Exception {
approveAccessTokenGrant("http://anywhere?key=value", true);
// Setting the redirect uri directly in the request shoiuld override the saved value
context.getAccessTokenRequest().set("redirect_uri", "http://nowhere.com");
try {
assertNotNull(context.getAccessToken());
fail("Expected RedirectMismatchException");
}
catch (RedirectMismatchException e) {
}
assertEquals(HttpStatus.BAD_REQUEST, tokenEndpointResponse.getStatusCode());
}
private void confirmTokenRequestError(String clientId, String redirectUri, String code, String scope,
HttpStatus status, String errorMessage) {
@SuppressWarnings("rawtypes")
ResponseEntity<Map> response = requestToken(clientId, redirectUri, code, scope);
assertEquals(status, response.getStatusCode());
assertTrue(response.getBody().containsKey("error"));
assertEquals(errorMessage, response.getBody().get("error"));
}
private String getAuthorizationCode(String clientId, String redirectUri, String scope) {
String cookie = loginAndGetConfirmationPage(clientId, redirectUri, scope);
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));
headers.set("Cookie", cookie);
MultiValueMap<String, String> formData = new LinkedMultiValueMap<String, String>();
formData.add("user_oauth_approval", "true");
ResponseEntity<Void> result = serverRunning.postForStatus("/sparklr2/oauth/authorize", headers, formData);
assertEquals(HttpStatus.FOUND, result.getStatusCode());
// Get the authorization code using the same session
return getAuthorizationCode(result);
}
private ResponseEntity<Void> attemptToGetConfirmationPage(String clientId, String redirectUri) {
if (cookie == null) {
cookie = loginAndGrabCookie();
}
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));
headers.set("Cookie", cookie);
return serverRunning.getForResponse(getAuthorizeUrl(clientId, redirectUri, "read"), headers);
}
private String loginAndGetConfirmationPage(String clientId, String redirectUri, String scope) {
String cookie = loginAndGrabCookie();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));
headers.set("Cookie", cookie);
UriBuilder uri = serverRunning.buildUri("/sparklr2/oauth/authorize").queryParam("response_type", "code")
.queryParam("state", "mystateid").queryParam("scope", scope);
if (clientId != null) {
uri.queryParam("client_id", clientId);
}
if (redirectUri != null) {
uri.queryParam("redirect_uri", redirectUri);
}
ResponseEntity<String> response = serverRunning.getForString(uri.pattern(), headers, uri.params());
// The confirm access page should be returned
assertTrue(response.getBody().contains("Please Confirm"));
return cookie;
}
private String getAuthorizeUrl(String clientId, String redirectUri, String scope) {
UriBuilder uri = serverRunning.buildUri("/sparklr2/oauth/authorize").queryParam("response_type", "code")
.queryParam("state", "mystateid").queryParam("scope", scope);
if (clientId != null) {
uri.queryParam("client_id", clientId);
}
if (redirectUri != null) {
uri.queryParam("redirect_uri", redirectUri);
}
return uri.build().toString();
}
@SuppressWarnings("rawtypes")
private ResponseEntity<Map> requestToken(String clientId, String redirectUri, String cookie, String scope) {
MultiValueMap<String, String> formData = getTokenFormData(clientId, redirectUri, cookie, scope);
ResponseEntity<Map> map = serverRunning.postForMap("/sparklr2/oauth/token", formData);
HttpHeaders responseHeaders = map.getHeaders();
assertTrue("Missing no-store: " + responseHeaders, responseHeaders.get("Cache-Control").contains("no-store"));
return map;
}
private MultiValueMap<String, String> getTokenFormData(String clientId, String redirectUri, String code,
String scope) {
MultiValueMap<String, String> formData = new LinkedMultiValueMap<String, String>();
formData.add("grant_type", "authorization_code");
formData.add("client_id", clientId);
formData.add("scope", scope);
formData.add("redirect_uri", redirectUri);
formData.add("state", "mystateid");
if (code != null) {
formData.add("code", code);
}
return formData;
}
private String getAuthorizationCode(HttpEntity<Void> result) {
String location = result.getHeaders().getLocation().toString();
assertTrue(location.matches("http://.*code=.+"));
String code = null;
String state = null;
for (StringTokenizer queryTokens = new StringTokenizer(result.getHeaders().getLocation().getQuery(), "&="); queryTokens
.hasMoreTokens();) {
String token = queryTokens.nextToken();
if ("code".equals(token)) {
if (code != null) {
fail("shouldn't have returned more than one code.");
}
code = queryTokens.nextToken();
}
else if ("state".equals(token)) {
state = queryTokens.nextToken();
}
}
assertEquals("mystateid", state);
assertNotNull(code);
return code;
}
private String loginAndGrabCookie() {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));
MultiValueMap<String, String> formData = new LinkedMultiValueMap<String, String>();
formData.add("j_username", "marissa");
formData.add("j_password", "koala");
// Should be redirected to the original URL, but now authenticated
ResponseEntity<Void> result = serverRunning.postForStatus("/sparklr2/login.do", headers, formData);
assertEquals(HttpStatus.FOUND, result.getStatusCode());
assertTrue(result.getHeaders().containsKey("Set-Cookie"));
return result.getHeaders().getFirst("Set-Cookie");
}
private void approveAccessTokenGrant(String currentUri, boolean approved) {
AccessTokenRequest request = context.getAccessTokenRequest();
AuthorizationCodeResourceDetails resource = (AuthorizationCodeResourceDetails) context.getResource();
request.setCookie(cookie);
if (currentUri != null) {
request.setCurrentUri(currentUri);
}
String location = null;
try {
// First try to obtain the access token...
assertNotNull(context.getAccessToken());
fail("Expected UserRedirectRequiredException");
}
catch (UserRedirectRequiredException e) {
// Expected and necessary, so that the correct state is set up in the request...
location = e.getRedirectUri();
}
assertTrue(location.startsWith(resource.getUserAuthorizationUri()));
assertNull(request.getAuthorizationCode());
try {
// Now try again and the token provider will redirect for user approval...
assertNotNull(context.getAccessToken());
fail("Expected UserRedirectRequiredException");
}
catch (UserApprovalRequiredException e) {
// Expected and necessary, so that the user can approve the grant...
location = e.getApprovalUri();
}
assertTrue(location.startsWith(resource.getUserAuthorizationUri()));
assertNull(request.getAuthorizationCode());
// The approval (will be processed on the next attempt to obtain an access token)...
request.set(AuthorizationEndpoint.USER_OAUTH_APPROVAL, "" + approved);
}
static class MyLessTrustedClient extends AuthorizationCodeResourceDetails {
public MyLessTrustedClient(Object target) {
super();
setClientId("my-less-trusted-client");
setScope(Arrays.asList("read"));
setId(getClientId());
TestAuthorizationCodeProvider test = (TestAuthorizationCodeProvider) target;
setAccessTokenUri(test.serverRunning.getUrl("/sparklr2/oauth/token"));
setUserAuthorizationUri(test.serverRunning.getUrl("/sparklr2/oauth/authorize"));
}
}
static class MyClientWithRegisteredRedirect extends MyLessTrustedClient {
public MyClientWithRegisteredRedirect(Object target) {
super(target);
setClientId("my-client-with-registered-redirect");
setPreEstablishedRedirectUri("http://anywhere?key=value");
}
}
}
/*
* Copyright 2006-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.springframework.security.oauth2.provider;
import org.junit.Test;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.core.io.FileSystemResource;
/**
* @author Dave Syer
*
*/
public class TestBootstrap {
@Test
public void testRootContext() throws Exception {
GenericXmlApplicationContext context = new GenericXmlApplicationContext(new FileSystemResource("src/main/webapp/WEB-INF/spring-servlet.xml"));
context.close();
}
}
/*
* Copyright 2006-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.springframework.security.oauth.examples.tonr;
import org.junit.Test;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.core.io.FileSystemResource;
/**
* @author Dave Syer
*
*/
public class TestBootstrap {
@Test
public void testRootContext() throws Exception {
GenericXmlApplicationContext context = new GenericXmlApplicationContext(new FileSystemResource("src/main/webapp/WEB-INF/spring-servlet.xml"));
context.close();
}
}
package org.springframework.security.oauth.examples.tonr;
import static org.junit.Assert.assertEquals;
import java.util.Arrays;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.context.DefaultOAuth2ClientContext;
import org.springframework.security.oauth2.client.token.DefaultAccessTokenRequest;
import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsAccessTokenProvider;
import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.web.client.RestTemplate;
/**
* @author Ryan Heaton
* @author Dave Syer
*/
public class TestClientCredentialsGrant {
@Rule
public ServerRunning serverRunning = ServerRunning.isRunning();
@Test
public void testConnectDirectlyToResourceServer() throws Exception {
ClientCredentialsResourceDetails resource = new ClientCredentialsResourceDetails();
resource.setAccessTokenUri(serverRunning.getUrl("/sparklr2/oauth/token"));
resource.setClientId("my-client-with-registered-redirect");
resource.setId("sparklr");
resource.setScope(Arrays.asList("trust"));
ClientCredentialsAccessTokenProvider provider = new ClientCredentialsAccessTokenProvider();
OAuth2AccessToken accessToken = provider.obtainAccessToken(resource, new DefaultAccessTokenRequest());
// TODO: should this work? The client id is different.
OAuth2RestTemplate template = new OAuth2RestTemplate(resource, new DefaultOAuth2ClientContext(accessToken));
String result = template.getForObject(serverRunning.getUrl("/sparklr2/photos/trusted/message"), String.class);
// System.err.println(result);
assertEquals("Hello, Trusted Client", result);
}
@Test
public void testConnectThroughClientApp() throws Exception {
// tonr is a trusted client of sparklr for this resource
RestTemplate template = new RestTemplate();
String result = template.getForObject(serverRunning.getUrl("/tonr2/trusted/message"), String.class);
// System.err.println(result);
assertEquals("{\"message\":\"Hello, Trusted Client\"}", result);
}
}
package org.springframework.security.oauth2.provider;
import static org.junit.Assert.assertNull;
import java.util.Arrays;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.security.oauth2.client.test.OAuth2ContextConfiguration;
import org.springframework.security.oauth2.client.test.OAuth2ContextSetup;
import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.TestClientCredentialsProvider.ClientCredentials;
/**
* @author Ryan Heaton
* @author Dave Syer
*/
@OAuth2ContextConfiguration(ClientCredentials.class)
public class TestClientCredentialsProvider {
@Rule
public ServerRunning serverRunning = ServerRunning.isRunning();
@Rule
public OAuth2ContextSetup context = OAuth2ContextSetup.standard(serverRunning);
/**
* tests the basic provider
*/
@Test
public void testPostForToken() throws Exception {
OAuth2AccessToken token = context.getAccessToken();
assertNull(token.getRefreshToken());
}
static class ClientCredentials extends ClientCredentialsResourceDetails {
public ClientCredentials(Object target) {
setClientId("my-client-with-registered-redirect");
setScope(Arrays.asList("read"));
setId(getClientId());
TestClientCredentialsProvider test = (TestClientCredentialsProvider) target;
setAccessTokenUri(test.serverRunning.getUrl("/sparklr2/oauth/token"));
}
}
}
package org.springframework.security.oauth2.provider;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
import java.util.Arrays;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.client.UserRedirectRequiredException;
import org.springframework.security.oauth2.client.test.BeforeOAuth2Context;
import org.springframework.security.oauth2.client.test.OAuth2ContextConfiguration;
import org.springframework.security.oauth2.client.test.OAuth2ContextSetup;
import org.springframework.security.oauth2.client.token.grant.implicit.ImplicitResourceDetails;
import org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
/**
* @author Ryan Heaton
* @author Dave Syer
*/
public class TestImplicitProvider {
@Rule
public ServerRunning serverRunning = ServerRunning.isRunning();
@Rule
public OAuth2ContextSetup context = OAuth2ContextSetup.standard(serverRunning);
private String cookie;
@BeforeOAuth2Context
public void loginAndExtractCookie() {
MultiValueMap<String, String> formData;
formData = new LinkedMultiValueMap<String, String>();
formData.add("j_username", "marissa");
formData.add("j_password", "koala");
String location = "/sparklr2/login.do";
ResponseEntity<Void> result = serverRunning.postForStatus(location, formData);
assertEquals(HttpStatus.FOUND, result.getStatusCode());
String cookie = result.getHeaders().getFirst("Set-Cookie");
assertNotNull("Expected cookie in " + result.getHeaders(), cookie);
this.cookie = cookie;
}
@Test(expected = UserRedirectRequiredException.class)
@OAuth2ContextConfiguration(resource = AutoApproveImplicit.class, initialize = false)
public void testRedirectRequiredForAuthentication() throws Exception {
context.getAccessToken();
}
@Test
@OAuth2ContextConfiguration(resource = AutoApproveImplicit.class, initialize = false)
public void testPostForAutomaticApprovalToken() throws Exception {
context.getAccessTokenRequest().setCookie(cookie);
assertNotNull(context.getAccessToken());
}
@Test
@OAuth2ContextConfiguration(resource = NonAutoApproveImplicit.class, initialize = false)
public void testPostForNonAutomaticApprovalToken() throws Exception {
context.getAccessTokenRequest().setCookie(cookie);
try {
assertNotNull(context.getAccessToken());
fail("Expected UserRedirectRequiredException");
}
catch (UserRedirectRequiredException e) {
// ignore
}
// add user approval parameter for the second request
context.getAccessTokenRequest().add(AuthorizationEndpoint.USER_OAUTH_APPROVAL, "true");
assertNotNull(context.getAccessToken());
}
static class AutoApproveImplicit extends ImplicitResourceDetails {
public AutoApproveImplicit(Object target) {
super();
setClientId("my-less-trusted-autoapprove-client");
setScope(Arrays.asList("read"));
setId(getClientId());
setPreEstablishedRedirectUri("http://anywhere");
TestImplicitProvider test = (TestImplicitProvider) target;
setAccessTokenUri(test.serverRunning.getUrl("/sparklr2/oauth/authorize"));
setUserAuthorizationUri(test.serverRunning.getUrl("/sparklr2/oauth/authorize"));
}
}
static class NonAutoApproveImplicit extends AutoApproveImplicit {
public NonAutoApproveImplicit(Object target) {
super(target);
setClientId("my-less-trusted-client");
}
}
}
package org.springframework.security.oauth.examples.tonr;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import java.util.Date;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.context.DefaultOAuth2ClientContext;
import org.springframework.security.oauth2.client.token.AccessTokenRequest;
import org.springframework.security.oauth2.client.token.DefaultAccessTokenRequest;
import org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordResourceDetails;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
/**
* @author Dave Syer
*/
public class TestRefreshTokenGrant {
@Rule
public ServerRunning serverRunning = ServerRunning.isRunning();
private OAuth2AccessToken existingToken;
private ResourceOwnerPasswordResourceDetails resource;
@Before
public void setup() {
resource = new ResourceOwnerPasswordResourceDetails();
resource.setAccessTokenUri(serverRunning.getUrl("/sparklr2/oauth/token"));
resource.setClientId("my-trusted-client");
resource.setId("sparklr");
resource.setScope(Arrays.asList("trust"));
resource.setUsername("marissa");
resource.setPassword("koala");
OAuth2RestTemplate template = new OAuth2RestTemplate(resource);
existingToken = template.getAccessToken();
((DefaultOAuth2AccessToken)existingToken).setExpiration(new Date(0L));
SecurityContextImpl securityContext = new SecurityContextImpl();
securityContext.setAuthentication(new TestingAuthenticationToken("marissa", "koala", "ROLE_USER"));
SecurityContextHolder.setContext(securityContext);
}
@Test
public void testConnectDirectlyToResourceServer() throws Exception {
assertNotNull(existingToken.getRefreshToken());
// It won't be expired on the server, but we can force the client to refresh it
assertTrue(existingToken.isExpired());
AccessTokenRequest request = new DefaultAccessTokenRequest();
request.setExistingToken(existingToken);
OAuth2RestTemplate template = new OAuth2RestTemplate(resource, new DefaultOAuth2ClientContext(request));
String result = template.getForObject(serverRunning.getUrl("/sparklr2/photos/user/message"), String.class);
assertEquals("Hello, Trusted User marissa", result);
assertFalse("Tokens match so there was no refresh", existingToken.equals(template.getAccessToken()));
}
}
package org.springframework.security.oauth2.provider;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import java.util.Map;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
/**
* @author Ryan Heaton
* @author Dave Syer
*/
public class TestRefreshTokenSupport {
@Rule
public ServerRunning serverRunning = ServerRunning.isRunning();
/**
* tests a happy-day flow of the refresh token provider.
*/
@Test
public void testHappyDay() throws Exception {
OAuth2AccessToken accessToken = getAccessToken("read", "my-trusted-client");
// now use the refresh token to get a new access token.
assertNotNull(accessToken.getRefreshToken());
OAuth2AccessToken newAccessToken = refreshAccessToken(accessToken.getRefreshToken().getValue());
assertFalse(newAccessToken.getValue().equals(accessToken.getValue()));
// make sure the new access token can be used.
verifyTokenResponse(newAccessToken.getValue(), HttpStatus.OK);
// make sure the old access token isn't valid anymore.
verifyTokenResponse(accessToken.getValue(), HttpStatus.UNAUTHORIZED);
}
private void verifyTokenResponse(String accessToken, HttpStatus status) {
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", String.format("%s %s", OAuth2AccessToken.BEARER_TYPE, accessToken));
assertEquals(status, serverRunning.getStatusCode("/sparklr2/photos?format=json", headers));
}
private OAuth2AccessToken refreshAccessToken(String refreshToken) {
MultiValueMap<String, String> formData = new LinkedMultiValueMap<String, String>();
formData.add("grant_type", "refresh_token");
formData.add("client_id", "my-trusted-client");
formData.add("refresh_token", refreshToken);
@SuppressWarnings("rawtypes")
ResponseEntity<Map> response = serverRunning.postForMap("/sparklr2/oauth/token", formData);
assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals("no-store", response.getHeaders().getFirst("Cache-Control"));
@SuppressWarnings("unchecked")
OAuth2AccessToken newAccessToken = DefaultOAuth2AccessToken.valueOf(response.getBody());
return newAccessToken;
}
private OAuth2AccessToken getAccessToken(String scope, String clientId) throws Exception {
MultiValueMap<String, String> formData = getTokenFormData(scope, clientId);
@SuppressWarnings("rawtypes")
ResponseEntity<Map> response = serverRunning.postForMap("/sparklr2/oauth/token", formData);
assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals("no-store", response.getHeaders().getFirst("Cache-Control"));
@SuppressWarnings("unchecked")
OAuth2AccessToken accessToken = DefaultOAuth2AccessToken.valueOf(response.getBody());
return accessToken;
}
private MultiValueMap<String, String> getTokenFormData(String scope, String clientId) {
MultiValueMap<String, String> formData = new LinkedMultiValueMap<String, String>();
formData.add("grant_type", "password");
if (clientId != null) {
formData.add("client_id", clientId);
}
formData.add("scope", scope);
formData.add("username", "marissa");
formData.add("password", "koala");
return formData;
}
}
package org.springframework.security.oauth.examples.tonr;
import static org.junit.Assert.assertEquals;
import java.util.Arrays;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordResourceDetails;
/**
* @author Dave Syer
*/
public class TestResourceOwnerPasswordGrant {
@Rule
public ServerRunning serverRunning = ServerRunning.isRunning();
@Test
public void testConnectDirectlyToResourceServer() throws Exception {
ResourceOwnerPasswordResourceDetails resource = new ResourceOwnerPasswordResourceDetails();
resource.setAccessTokenUri(serverRunning.getUrl("/sparklr2/oauth/token"));
resource.setClientId("my-trusted-client");
resource.setId("sparklr");
resource.setScope(Arrays.asList("trust"));
resource.setUsername("marissa");
resource.setPassword("koala");
OAuth2RestTemplate template = new OAuth2RestTemplate(resource);
String result = template.getForObject(serverRunning.getUrl("/sparklr2/photos/user/message"), String.class);
// System.err.println(result);
assertEquals("Hello, Trusted User marissa", result);
}
}
package org.springframework.security.oauth2.provider;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.security.oauth2.client.test.BeforeOAuth2Context;
import org.springframework.security.oauth2.client.test.OAuth2ContextConfiguration;
import org.springframework.security.oauth2.client.test.OAuth2ContextSetup;
import org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordAccessTokenProvider;
import org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordResourceDetails;
import org.springframework.security.oauth2.common.AuthenticationScheme;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.ResponseExtractor;
/**
* @author Ryan Heaton
* @author Dave Syer
*/
public class TestResourceOwnerPasswordProvider {
@Rule
public ServerRunning serverRunning = ServerRunning.isRunning();
@Rule
public OAuth2ContextSetup context = OAuth2ContextSetup.standard(serverRunning);
private ClientHttpResponse tokenEndpointResponse;
@BeforeOAuth2Context
public void setupAccessTokenProvider() {
ResourceOwnerPasswordAccessTokenProvider accessTokenProvider = new ResourceOwnerPasswordAccessTokenProvider() {
private ResponseExtractor<OAuth2AccessToken> extractor = super.getResponseExtractor();
private ResponseErrorHandler errorHandler = super.getResponseErrorHandler();
@Override
protected ResponseErrorHandler getResponseErrorHandler() {
return new DefaultResponseErrorHandler() {
public void handleError(ClientHttpResponse response) throws IOException {
response.getHeaders();
response.getStatusCode();
tokenEndpointResponse = response;
errorHandler.handleError(response);
}
};
}
@Override
protected ResponseExtractor<OAuth2AccessToken> getResponseExtractor() {
return new ResponseExtractor<OAuth2AccessToken>() {
public OAuth2AccessToken extractData(ClientHttpResponse response) throws IOException {
response.getHeaders();
response.getStatusCode();
tokenEndpointResponse = response;
return extractor.extractData(response);
}
};
}
};
context.setAccessTokenProvider(accessTokenProvider);
}
@Test
public void testUnauthenticated() throws Exception {
// first make sure the resource is actually protected.
assertEquals(HttpStatus.UNAUTHORIZED, serverRunning.getStatusCode("/sparklr2/photos?format=json"));
}
@Test
public void testUnauthenticatedErrorMessage() throws Exception {
HttpHeaders headers = new HttpHeaders();
ResponseEntity<Void> response = serverRunning.getForResponse("/sparklr2/photos?format=json", headers);
assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode());
String authenticate = response.getHeaders().getFirst("WWW-Authenticate");
assertTrue("Wrong header: " + authenticate, authenticate.contains("error=\"unauthorized\""));
}
@Test
public void testInvalidTokenErrorMessage() throws Exception {
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Bearer FOO");
ResponseEntity<Void> response = serverRunning.getForResponse("/sparklr2/photos?format=json", headers);
assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode());
String authenticate = response.getHeaders().getFirst("WWW-Authenticate");
assertTrue("Wrong header: " + authenticate, authenticate.contains("error=\"invalid_token\""));
}
@Test
@OAuth2ContextConfiguration(ResourceOwner.class)
public void testTokenObtainedWithHeaderAuthentication() throws Exception {
assertEquals(HttpStatus.OK, serverRunning.getStatusCode("/sparklr2/photos?format=json"));
}
@Test
@OAuth2ContextConfiguration(ResourceOwnerQuery.class)
public void testTokenObtainedWithQueryAuthentication() throws Exception {
assertEquals(HttpStatus.OK, serverRunning.getStatusCode("/sparklr2/photos?format=json"));
}
@Test
@OAuth2ContextConfiguration(resource = ResourceOwnerNoSecretProvided.class, initialize = false)
public void testTokenNotGrantedIfSecretNotProvided() throws Exception {
try {
context.getAccessToken();
}
catch (HttpClientErrorException e) {
assertEquals(HttpStatus.UNAUTHORIZED, e.getStatusCode());
List<String> values = tokenEndpointResponse.getHeaders().get("WWW-Authenticate");
assertEquals(1, values.size());
assertEquals("Bearer realm=\"sparklr2\", error=\"unauthorized\", error_description=\"Bad credentials\"", values.get(0));
}
}
@Test
@OAuth2ContextConfiguration(ResourceOwnerSecretProvidedInForm.class)
public void testSecretProvidedInForm() throws Exception {
assertEquals(HttpStatus.OK, serverRunning.getStatusCode("/sparklr2/photos?format=json"));
}
@Test
@OAuth2ContextConfiguration(ResourceOwnerSecretProvided.class)
public void testSecretProvidedInHeader() throws Exception {
assertEquals(HttpStatus.OK, serverRunning.getStatusCode("/sparklr2/photos?format=json"));
}
@Test
@OAuth2ContextConfiguration(resource = InvalidGrantType.class, initialize = false)
public void testInvalidGrantType() throws Exception {
// The error comes back as additional information because OAuth2AccessToken is so extensible!
try {
context.getAccessToken();
}
catch (OAuth2Exception e) {
assertEquals("invalid_grant", e.getOAuth2ErrorCode());
}
assertEquals(HttpStatus.BAD_REQUEST, tokenEndpointResponse.getStatusCode());
List<String> newCookies = tokenEndpointResponse.getHeaders().get("Set-Cookie");
if (newCookies != null && !newCookies.isEmpty()) {
fail("No cookies should be set. Found: " + newCookies.get(0) + ".");
}
}
@Test
public void testUserMessageIsProtectedResource() throws Exception {
assertEquals(HttpStatus.UNAUTHORIZED, serverRunning.getStatusCode("/sparklr2/photos/user/message"));
}
@Test
@OAuth2ContextConfiguration(ResourceOwnerWithTrustedClient.class)
public void testClientRoleBasedSecurity() throws Exception {
assertEquals(HttpStatus.OK, serverRunning.getStatusCode("/sparklr2/photos/user/message"));
}
/**
* tests a happy-day flow of the native application provider.
*/
@Test
@OAuth2ContextConfiguration(ResourceOwnerWithTrustedClient.class)
public void testUnsupportedMediaType() throws Exception {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_XML));
// Oddly enough this passes - the payload is a String so the message converter thinks it can handle it
// the caller will get a surprise when he finds that the response is not actually XML, but that's a different
// story.
assertEquals(HttpStatus.OK, serverRunning.getStatusCode("/sparklr2/photos/user/message", headers));
}
/**
* tests that we get the correct error response if the media type is unacceptable.
*/
@Test
public void testUnsupportedMediaTypeWithInvalidToken() throws Exception {
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", String.format("%s %s", OAuth2AccessToken.BEARER_TYPE, "FOO"));
headers.setAccept(Arrays.asList(MediaType.valueOf("text/foo")));
assertEquals(HttpStatus.NOT_ACCEPTABLE, serverRunning.getStatusCode("/sparklr2/photos/user/message", headers));
}
static class ResourceOwner extends ResourceOwnerPasswordResourceDetails {
public ResourceOwner(Object target) {
setClientId("my-trusted-client");
setScope(Arrays.asList("read"));
setId(getClientId());
setUsername("marissa");
setPassword("koala");
TestResourceOwnerPasswordProvider test = (TestResourceOwnerPasswordProvider) target;
setAccessTokenUri(test.serverRunning.getUrl("/sparklr2/oauth/token"));
}
}
static class ResourceOwnerQuery extends ResourceOwner {
public ResourceOwnerQuery(Object target) {
super(target);
setAuthenticationScheme(AuthenticationScheme.query);
}
}
static class ResourceOwnerNoSecretProvided extends ResourceOwner {
public ResourceOwnerNoSecretProvided(Object target) {
super(target);
setClientId("my-trusted-client-with-secret");
}
}
static class ResourceOwnerSecretProvided extends ResourceOwner {
public ResourceOwnerSecretProvided(Object target) {
super(target);
setClientId("my-trusted-client-with-secret");
setClientSecret("somesecret");
}
}
static class ResourceOwnerSecretProvidedInForm extends ResourceOwnerSecretProvided {
public ResourceOwnerSecretProvidedInForm(Object target) {
super(target);
setAuthenticationScheme(AuthenticationScheme.form);
}
}
static class InvalidGrantType extends ResourceOwner {
public InvalidGrantType(Object target) {
super(target);
setClientId("my-untrusted-client-with-registered-redirect");
}
}
static class ResourceOwnerWithTrustedClient extends ResourceOwner {
public ResourceOwnerWithTrustedClient(Object target) {
super(target);
setClientId("my-trusted-client");
setScope(Arrays.asList("trust"));
}
}
}
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<filter>
<filter-name>clientCredentialsTokenEndpointFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>contextAttribute</param-name>
<param-value>org.springframework.web.servlet.FrameworkServlet.CONTEXT.spring</param-value>
</init-param>
</filter>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>contextAttribute</param-name>
<param-value>org.springframework.web.servlet.FrameworkServlet.CONTEXT.spring</param-value>
</init-param>
</filter>
<filter>
<filter-name>oauth2EndpointUrlFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>contextAttribute</param-name>
<param-value>org.springframework.web.servlet.FrameworkServlet.CONTEXT.spring</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>clientCredentialsTokenEndpointFilter</filter-name>
<url-pattern>/token</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>oauth2EndpointUrlFilter</filter-name>
<url-pattern>/authorize</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>oauth2EndpointUrlFilter</filter-name>
<url-pattern>/token</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>contextAttribute</param-name>
<param-value>org.springframework.web.servlet.FrameworkServlet.CONTEXT.spring</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment