Skip to content

Instantly share code, notes, and snippets.

@dsyer
Created October 26, 2011 16:28
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 7 You must be signed in to fork a gist
  • Save dsyer/1316904 to your computer and use it in GitHub Desktop.
Save dsyer/1316904 to your computer and use it in GitHub Desktop.
Dave Syer: Demos for s2gx2011
target/
*/src/main/*/META-INF/
.access_token
.result
.classpath
.project
.DS_Store
.settings/
*.iml
*.iws
*.ipr
.idea/
cargo-installs/
<?xml version="1.0" encoding="UTF-8"?>
<beansProjectDescription>
<version>1</version>
<pluginVersion><![CDATA[2.8.0.201110170010-RELEASE]]></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>
<?xml version="1.0" encoding="UTF-8"?>
<beansProjectDescription>
<version>1</version>
<pluginVersion><![CDATA[2.8.0.201110170010-RELEASE]]></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>

Demos for s2gx2011

<%@ taglib prefix="authz"
uri="http://www.springframework.org/security/tags"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/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="/resources/style.css"/>" />
</head>
<body>
<h1>OAuth2 Authorization</h1>
<div id="content">
<c:if test="${error}">
<div class="error">
<h2>Woops!</h2>
<p>${error}</p>
</div>
</c:if>
<authz:authorize ifAllGranted="ROLE_USER">
<h2>Please Confirm</h2>
<p>Do you authorize ${client.clientId} to access your protected
resources in scope ${auth_request.scope}.</p>
<form id="confirmationForm" name="confirmationForm"
action="${options.confirm.location}" method="POST">
<input name="${options.confirm.key}"
value="${options.confirm.value}" type="hidden" /> <label><input
name="authorize" value="Authorize" type="submit">
</label>
</form>
<form id="denialForm" name="denialForm"
action="${options.deny.location}" method="POST">
<input name="${options.deny.key}" value="${options.deny.value}"
type="hidden" /> <label><input name="deny" value="Deny"
type="submit">
</label>
</form>
</authz:authorize>
</div>
<div id="footer">Demo only</div>
</body>
</html>
package org.cloudfoundry.identity.uaa.web;
import java.security.Principal;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.cloudfoundry.identity.uaa.web.OpenIdProviderController.Openid;
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.RequestMethod;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.context.request.WebRequest;
/**
* Controller for retrieving the model for and displaying the confirmation page for access to a protected resource.
*
* @author Ryan Heaton
* @author Dave Syer
*/
@Controller
@SessionAttributes(types = AuthorizationRequest.class)
public class AccessController {
private ClientDetailsService clientDetailsService;
@ModelAttribute("identity")
public String getIdentity(HttpSession session) {
Openid openid = (Openid) session.getAttribute("openid");
return openid == null ? null : openid.getIdentity();
}
@RequestMapping("/oauth/confirm_access")
public String confirm(@ModelAttribute AuthorizationRequest clientAuth, Map<String, Object> model, final HttpServletRequest request)
throws Exception {
if (clientAuth == null) {
model.put(
"error",
"No client authentication token is present in the request, so we cannot confirm access (we don't know what you are asking for).");
// response.sendError(HttpServletResponse.SC_BAD_REQUEST);
}
else {
ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId());
model.put("auth_request", clientAuth);
model.put("client", client);
model.put("message",
"To confirm or deny access POST to the following locations with the parameters requested.");
Map<String, Object> options = new HashMap<String, Object>() {
{
put("confirm", new HashMap<String, String>() {
{
put("location", getLocation(request, "oauth/authorize"));
put("key", "user_oauth_approval");
put("value", "true");
}
});
put("deny", new HashMap<String, String>() {
{
put("location", getLocation(request, "oauth/authorize"));
put("key", "user_oauth_approval");
put("value", "false");
}
});
}
};
model.put("options", options);
}
return "access_confirmation";
}
@RequestMapping(value = "/login", method = RequestMethod.GET)
public String defaultLoginPage(Map<String, Object> model, final WebRequest request) {
String username = "";
if (model.containsKey("claimed_identity")) {
String identity = (String) model.get("claimed_identity");
username = extractUserName(identity);
}
model.put("username", username);
model.put(
"message",
"You are logged out. Please POST to the location provided with form parameters according to the type of client you are.");
Map<String, Object> options = new HashMap<String, Object>() {
{
put("shell", new HashMap<String, Object>() {
{
put("location", getLocation(request, "oauth/token"));
put("parameters", Arrays.asList("username", "password", "grant_type=password", "client_id"));
}
});
put("browser", new HashMap<String, Object>() {
{
put("location", getLocation(request, "login.do"));
put("parameters", getPrompts());
}
});
}
};
model.put("options", options);
return "login";
}
private String extractUserName(String identity) {
if (identity == null) {
return "";
}
String[] split = identity.split("/");
return split.length == 1 ? identity : split[split.length - 1];
}
@RequestMapping(value = { "/", "/home" })
public String homePage(Map<String, Object> model, WebRequest request, Principal principal) {
Object error = request.getAttribute("SPRING_SECURITY_403_EXCEPTION", WebRequest.SCOPE_REQUEST);
if (error != null) {
model.put("error", "You don't have access to this resource (" + error + ")");
}
model.put("message", "You are logged in. Log out by sending a GET to the location provided.");
model.put("location", "http:" + request.getHeader("Host") + request.getContextPath() + "/logout.do");
model.put("principal", principal);
return "home";
}
private Map<String, String[]> getPrompts() {
Map<String, String[]> prompts = new LinkedHashMap<String, String[]>();
prompts.put("username", new String[] { "text", "Username" });
prompts.put("password", new String[] { "hidden", "Password" });
return prompts;
}
@Autowired
public void setClientDetailsService(ClientDetailsService clientDetailsService) {
this.clientDetailsService = clientDetailsService;
}
private String getLocation(HttpServletRequest request, String path) {
return "http://" + request.getHeader("Host") + request.getContextPath() + "/" + path;
}
private String getLocation(WebRequest request, String path) {
return "http://" + request.getHeader("Host") + request.getContextPath() + "/" + path;
}
}
/*
* 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.cloudfoundry.identity.uaa.util;
import java.io.File;
import java.io.IOException;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
/**
* @author Dave Syer
*
*/
public class ApacheDsCleanup implements BeanFactoryPostProcessor {
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
try {
FileUtils.deleteDirectory(new File(System.getProperty("java.io.tmpdir"), "apacheds-spring-security"));
} catch (IOException e) {
throw new BeanInitializationException("Cannot clear Apache DS directory");
}
}
}
auth.url=http://dsyerauth.cloudfoundry.com/login
jdbc.driver=org.hsqldb.jdbcDriver
# jdbc.url=jdbc:hsqldb:mem:testdb;sql.enforce_strict_size=true
# use this one for a separate server process so you can inspect the results
# (or add it to system properties with -D to override at run time).
jdbc.url=jdbc:hsqldb:hsql://localhost:9005/samples
jdbc.user=sa
jdbc.password=
jdbc.testWhileIdle=false
jdbc.validationQuery=
openidProviderUrl=http://dsyerauth.cloudfoundry.com/openid
photoListUrl=http://dsyerapi.cloudfoundry.com/photos
photoUrlPattern=http://dsyerapp.cloudfoundry.com/photos/%s
photoUrlPassthruPattern=http://dsyerapi.cloudfoundry.com/photos/%s
accessTokenUri=http://dsyerauth.cloudfoundry.com/oauth/token
userAuthorizationUri=http://dsyerauth.cloudfoundry.com/oauth/authorize
jdbc.driver=
jdbc.url=
jdbc.user=
jdbc.password=
jdbc.testWhileIdle=false
jdbc.validationQuery=
openidProviderUrl=http://dsyerauth.cloudfoundry.com/openid
photoListUrl=http://dsyerapi.cloudfoundry.com/photos
photoUrlPattern=http://dsyerapp.cloudfoundry.com/photos/%s
photoUrlPassthruPattern=http://dsyerapi.cloudfoundry.com/photos/%s
accessTokenUri=http://dsyerauth.cloudfoundry.com/oauth/token
userAuthorizationUri=http://dsyerauth.cloudfoundry.com/oauth/authorize
jdbc.driver=
jdbc.url=
jdbc.user=
jdbc.password=
jdbc.testWhileIdle=false
jdbc.validationQuery=
auth.url=http://localhost:8080/auth/login
jdbc.driver=org.hsqldb.jdbcDriver
# jdbc.url=jdbc:hsqldb:mem:testdb;sql.enforce_strict_size=true
# use this one for a separate server process so you can inspect the results
# (or add it to system properties with -D to override at run time).
jdbc.url=jdbc:hsqldb:hsql://localhost:9005/samples
jdbc.user=sa
jdbc.password=
jdbc.testWhileIdle=false
jdbc.validationQuery=
openidProviderUrl=http://localhost:8080/auth/openid
# openidProviderUrl=https://www.google.com/accounts/o8/id
photoListUrl=http://localhost:8080/api/photos
photoUrlPattern=http://localhost:8080/app/photos/%s
photoUrlPassthruPattern=http://localhost:8080/api/photos/%s
accessTokenUri=http://localhost:8080/auth/oauth/token
userAuthorizationUri=http://localhost:8080/auth/oauth/authorize
jdbc.driver=org.hsqldb.jdbcDriver
# jdbc.url=jdbc:hsqldb:mem:testdb;sql.enforce_strict_size=true
# use this one for a separate server process so you can inspect the results
# (or add it to system properties with -D to override at run time).
jdbc.url=jdbc:hsqldb:hsql://localhost:9005/samples
jdbc.user=sa
jdbc.password=
jdbc.testWhileIdle=false
jdbc.validationQuery=
endpointUrl=http://localhost:8080/auth/openid/provider
openidProviderUrl=http://localhost:8080/auth/openid
# openidProviderUrl=https://www.google.com/accounts/o8/id
package org.cloudfoundry.identity.app.web;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.net.URI;
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.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
/**
* @author Dave Syer
*/
public class ApplicationIntegrationTests {
@Rule
public ServerRunning serverRunning = ServerRunning.isRunning();
/**
* tests the basic implicit provider
*/
@Test
public void testBasicHomePage() throws Exception {
HttpHeaders appHeaders = new HttpHeaders();
appHeaders.setAccept(Arrays.asList(MediaType.ALL));
URI uri = serverRunning.buildUri("/app/").build();
ResponseEntity<Void> result = serverRunning.getForResponse(uri.toString(), appHeaders);
assertEquals(HttpStatus.FOUND, result.getStatusCode());
String location = result.getHeaders().getLocation().toString();
String cookie = result.getHeaders().getFirst("Set-Cookie");
assertNotNull("Expected cookie in " + result.getHeaders(), cookie);
appHeaders.set("Cookie", cookie);
// redirect to /openid
assertTrue(location.contains("/app/login"));
result = serverRunning.getForResponse(location, appHeaders);
assertEquals(HttpStatus.FOUND, result.getStatusCode());
location = result.getHeaders().getLocation().toString();
// redirect to /auth
HttpHeaders authHeaders = new HttpHeaders();
authHeaders.setAccept(Arrays.asList(MediaType.ALL));
// redirect to /auth/openid/provider
assertTrue(location.contains("/openid/provider"));
result = serverRunning.getForResponse(location, authHeaders);
assertEquals(HttpStatus.FOUND, result.getStatusCode());
location = result.getHeaders().getLocation().toString();
// redirect to /auth/openid/authorize
assertTrue(location.contains("/openid/authorize"));
result = serverRunning.getForResponse(location, authHeaders);
assertEquals(HttpStatus.FOUND, result.getStatusCode());
location = result.getHeaders().getLocation().toString();
// redirect to /auth/login
assertTrue(location.contains("/login"));
ResponseEntity<String> response = serverRunning.getForString(location, authHeaders);
// should be directed to the login screen...
assertTrue(response.getBody().contains("auth/login.do"));
assertTrue(response.getBody().contains("username"));
assertTrue(response.getBody().contains("password"));
location = "/auth/login.do";
MultiValueMap<String, String> formData = new LinkedMultiValueMap<String, String>();
formData.add("username", "marissa");
formData.add("password", "koala");
response = serverRunning.postForPage(location, authHeaders, formData);
// should be directed to the approval screen...
assertTrue(response.getBody().contains("auth/openid/authorize"));
assertTrue(response.getBody().contains("approve"));
location = "/auth/openid/authorize";
formData = new LinkedMultiValueMap<String, String>();
formData.add("approve", "Approve");
// The cookie was set in the postForPage above (when we authenticated)
assertTrue(authHeaders.containsKey("Cookie"));
result = serverRunning.postForRedirect(location, authHeaders, formData);
assertNotNull(result.getHeaders().getLocation());
location = result.getHeaders().getLocation().toString();
// redirect to /app/j_spring_openid_security_check
assertTrue(location.contains("/app/login"));
result = serverRunning.getForResponse(location, appHeaders);
assertEquals(HttpStatus.FOUND, result.getStatusCode());
location = result.getHeaders().getLocation().toString();
response = serverRunning.getForString(location, appHeaders);
assertTrue("Wrong response: " + response.getBody(), response.getBody().contains("Sample Home Page"));
}
}
/*
* 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.cloudfoundry.identity.api.web;
import org.junit.Test;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.core.io.FileSystemResource;
/**
* @author Dave Syer
*
*/
public class BootstrapTests {
@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.cloudfoundry.identity.app.web;
import org.junit.Test;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.core.io.FileSystemResource;
/**
* @author Dave Syer
*
*/
public class BootstrapTests {
@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.cloudfoundry.identity.uaa.web;
import java.io.File;
import java.io.IOException;
import org.apache.commons.io.FileUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.core.io.FileSystemResource;
/**
* @author Dave Syer
*
*/
public class BootstrapTests {
@After
@Before
public void close() throws IOException {
FileUtils.deleteDirectory(new File(System.getProperty("java.io.tmpdir"), "apacheds-spring-security"));
}
@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.cloudfoundry.identity.app.web;
import org.junit.Test;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.core.io.FileSystemResource;
/**
* @author Dave Syer
*
*/
public class BootstrapTests {
@Test
public void testRootContext() throws Exception {
GenericXmlApplicationContext context = new GenericXmlApplicationContext(new FileSystemResource("src/main/webapp/WEB-INF/spring-servlet.xml"));
context.close();
}
}
/*
* 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.cloudfoundry.identity.api.web.mvc;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
* @author Dave Syer
*
*/
public class CompositeFilter implements Filter {
private List<Filter> filters = new ArrayList<Filter>();
public void setFilters(List<Filter> filters) {
this.filters = new ArrayList<Filter>(filters);
}
public void destroy() {
for (Filter filter : filters) {
filter.destroy();
}
}
public void init(FilterConfig config) throws ServletException {
for (Filter filter : filters) {
filter.init(config);
}
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
ServletException {
new VirtualFilterChain(chain, filters).doFilter(request, response);
}
private static class VirtualFilterChain implements FilterChain {
private final FilterChain originalChain;
private final List<Filter> additionalFilters;
private int currentPosition = 0;
private VirtualFilterChain(FilterChain chain, List<Filter> additionalFilters) {
this.originalChain = chain;
this.additionalFilters = additionalFilters;
}
public void doFilter(final ServletRequest request, final ServletResponse response) throws IOException, ServletException {
if (currentPosition == additionalFilters.size()) {
originalChain.doFilter(request, response);
} else {
currentPosition++;
Filter nextFilter = additionalFilters.get(currentPosition - 1);
nextFilter.doFilter(request, response, this);
}
}
}
}
drop table oauth_access_token;
drop table oauth_refresh_token;
create table oauth_access_token (
token_id VARCHAR(256),
token BLOB,
authentication BLOB,
refresh_token VARCHAR(256)
);
create table oauth_refresh_token (
token_id VARCHAR(256),
token BLOB,
authentication BLOB
);
drop table oauth_access_token;
drop table oauth_refresh_token;
create table oauth_access_token (
token_id VARCHAR(256),
token LONGVARBINARY,
authentication LONGVARBINARY,
refresh_token VARCHAR(256)
);
create table oauth_refresh_token (
token_id VARCHAR(256),
token LONGVARBINARY,
authentication LONGVARBINARY
);
/*
* 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.cloudfoundry.identity.openid.user;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
/**
* Customized {@code UserDetails} implementation.
*
* @author Luke Taylor
* @since 3.1
*/
public class CustomUserDetails extends User {
private String email;
private String name;
private boolean newUser;
public CustomUserDetails(String username, Collection<GrantedAuthority> authorities) {
super(username, "unused", authorities);
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public boolean isNewUser() {
return newUser;
}
public void setNewUser(boolean newUser) {
this.newUser = newUser;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
/*
* 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.cloudfoundry.identity.openid.user;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
/**
* Customized {@code UserDetails} implementation.
*
* @author Luke Taylor
* @since 3.1
*/
public class CustomUserDetails extends User {
private String email;
private String name;
private boolean newUser;
public CustomUserDetails(String username, Collection<GrantedAuthority> authorities) {
super(username, "unused", authorities);
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public boolean isNewUser() {
return newUser;
}
public void setNewUser(boolean newUser) {
this.newUser = newUser;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package org.cloudfoundry.identity.openid.user;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.openid.OpenIDAttribute;
import org.springframework.security.openid.OpenIDAuthenticationToken;
/**
* Custom UserDetailsService which accepts any OpenID user, "registering" new users in a map so they can be welcomed
* back to the site on subsequent logins.
*
* @author Luke Taylor
* @since 3.1
*/
public class CustomUserDetailsService implements UserDetailsService, AuthenticationUserDetailsService<OpenIDAuthenticationToken> {
private final Map<String, CustomUserDetails> registeredUsers = new HashMap<String, CustomUserDetails>();
private static final List<GrantedAuthority> DEFAULT_AUTHORITIES = AuthorityUtils.createAuthorityList("ROLE_USER");
/**
* Implementation of {@code UserDetailsService}. We only need this to satisfy the {@code RememberMeServices}
* requirements.
*/
public UserDetails loadUserByUsername(String id) throws UsernameNotFoundException {
UserDetails user = registeredUsers.get(id);
if (user == null) {
throw new UsernameNotFoundException(id);
}
return user;
}
/**
* Implementation of {@code AuthenticationUserDetailsService} which allows full access to the submitted
* {@code Authentication} object. Used by the OpenIDAuthenticationProvider.
*/
public UserDetails loadUserDetails(OpenIDAuthenticationToken token) {
String id = token.getIdentityUrl();
CustomUserDetails user = registeredUsers.get(id);
if (user != null) {
return user;
}
String email = null;
String firstName = null;
String lastName = null;
String fullName = null;
List<OpenIDAttribute> attributes = token.getAttributes();
for (OpenIDAttribute attribute : attributes) {
if (attribute.getName().equals("email")) {
email = attribute.getValues().get(0);
}
if (attribute.getName().equals("firstname")) {
firstName = attribute.getValues().get(0);
}
if (attribute.getName().equals("lastname")) {
lastName = attribute.getValues().get(0);
}
if (attribute.getName().equals("fullname")) {
fullName = attribute.getValues().get(0);
}
}
if (fullName == null) {
StringBuilder fullNameBldr = new StringBuilder();
if (firstName != null) {
fullNameBldr.append(firstName);
}
if (lastName != null) {
fullNameBldr.append(" ").append(lastName);
}
fullName = fullNameBldr.toString();
}
user = new CustomUserDetails(id, DEFAULT_AUTHORITIES);
user.setEmail(email);
user.setName(fullName);
registeredUsers.put(id, user);
user = new CustomUserDetails(id, DEFAULT_AUTHORITIES);
user.setEmail(email);
user.setName(fullName);
user.setNewUser(true);
return user;
}
}
package org.cloudfoundry.identity.openid.user;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.openid.OpenIDAttribute;
import org.springframework.security.openid.OpenIDAuthenticationToken;
/**
* Custom UserDetailsService which accepts any OpenID user, "registering" new users in a map so they can be welcomed
* back to the site on subsequent logins.
*
* @author Luke Taylor
* @since 3.1
*/
public class CustomUserDetailsService implements UserDetailsService, AuthenticationUserDetailsService<OpenIDAuthenticationToken> {
private final Map<String, CustomUserDetails> registeredUsers = new HashMap<String, CustomUserDetails>();
private static final List<GrantedAuthority> DEFAULT_AUTHORITIES = AuthorityUtils.createAuthorityList("ROLE_USER");
/**
* Implementation of {@code UserDetailsService}. We only need this to satisfy the {@code RememberMeServices}
* requirements.
*/
public UserDetails loadUserByUsername(String id) throws UsernameNotFoundException {
UserDetails user = registeredUsers.get(id);
if (user == null) {
throw new UsernameNotFoundException(id);
}
return user;
}
/**
* Implementation of {@code AuthenticationUserDetailsService} which allows full access to the submitted
* {@code Authentication} object. Used by the OpenIDAuthenticationProvider.
*/
public UserDetails loadUserDetails(OpenIDAuthenticationToken token) {
String id = token.getIdentityUrl();
CustomUserDetails user = registeredUsers.get(id);
if (user != null) {
return user;
}
String email = null;
String firstName = null;
String lastName = null;
String fullName = null;
List<OpenIDAttribute> attributes = token.getAttributes();
for (OpenIDAttribute attribute : attributes) {
if (attribute.getName().equals("email")) {
email = attribute.getValues().get(0);
}
if (attribute.getName().equals("firstname")) {
firstName = attribute.getValues().get(0);
}
if (attribute.getName().equals("lastname")) {
lastName = attribute.getValues().get(0);
}
if (attribute.getName().equals("fullname")) {
fullName = attribute.getValues().get(0);
}
}
if (fullName == null) {
StringBuilder fullNameBldr = new StringBuilder();
if (firstName != null) {
fullNameBldr.append(firstName);
}
if (lastName != null) {
fullNameBldr.append(" ").append(lastName);
}
fullName = fullNameBldr.toString();
}
user = new CustomUserDetails(id, DEFAULT_AUTHORITIES);
user.setEmail(email);
user.setName(fullName);
registeredUsers.put(id, user);
user = new CustomUserDetails(id, DEFAULT_AUTHORITIES);
user.setEmail(email);
user.setName(fullName);
user.setNewUser(true);
return user;
}
}
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<link type="text/css" rel="stylesheet" href="<c:url value="/resources/style.css"/>"/>
</head>
<body>
<h1>OpenID Sample Home Page (Photos)</h1>
<p>
Welcome<c:if test="${!principal.principal.newUser}"> back,</c:if> ${principal.principal.name}
</p>
<c:if test="${principal.principal.newUser}">
<p>
As a first time user of this site, your OpenID identity has been registered
by the application and will be recognized if you return.
</p>
</c:if>
<h3>Technical Information</h3>
<p>
Your principal object is....: ${principal}
</p>
<ul>
<li><a href="photos">Photos</a></li>
<li><a href="<c:url value="/"/>">Home</a></li>
<li><a href="j_spring_security_logout">Logout</a></li>
</ul>
</body>
</html>
<%@ taglib prefix="authz" uri="http://www.springframework.org/security/tags" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/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>Authorization Server Home</title>
<link type="text/css" rel="stylesheet" href="<c:url value="/resources/style.css"/>"/>
</head>
<body>
<h1>Authorization Server</h1>
<div id="content">
<h2>Home</h2>
<p>This is test page to ensure that your account login is working.</p>
<c:if test="${error}" >
<div class="error">
<h2>Woops!</h2>
<p>${error}</p>
</div>
</c:if>
<authz:authorize ifNotGranted="ROLE_USER">
<h2>You are logged in but do not have the user role</h2>
<div>You should never see this, but if you do, maybe you can <a href="<c:url value="/login"/>">log in here</a></div>
<br/>
</authz:authorize>
<authz:authorize ifAllGranted="ROLE_USER">
<h2>You are logged in</h2>
</authz:authorize>
<div style="text-align: center"><form action="<c:url value="/logout.do"/>"><input type="submit" value="Logout"/></form></div>
</div>
<div id="footer">Demo only</div>
</body>
</html>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<link type="text/css" rel="stylesheet" href="<c:url value="/resources/style.css"/>"/>
</head>
</head>
<body>
<h1>OpenID Sample Home Page (Hello)</h1>
<p>
Welcome<c:if test="${!principal.principal.newUser}"> back,</c:if> ${principal.principal.name}
</p>
<c:if test="${principal.principal.newUser}">
<p>
As a first time user of this site, your OpenID identity has been registered
by the application and will be recognized if you return.
</p>
</c:if>
<h3>Technical Information</h3>
<p>
Hello World. Your principal object is....: ${principal}
</p>
<ul>
<li><a href="<c:url value="/"/>">Home</a></li>
<li><a href="j_spring_security_logout">Logout</a></li>
</ul>
</body>
</html>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/auth"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="4"/>
</listAttribute>
<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="org.eclipse.m2e.launchconfig.classpathProvider"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.hsqldb.Server"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="auth"/>
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.m2e.launchconfig.sourcepathProvider"/>
</launchConfiguration>
<jsp:forward page="/home" />
<jsp:forward page="/home" />
/*!
* jQuery JavaScript Library v1.4.2
* http://jquery.com/
*
* Copyright 2010, John Resig
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* Includes Sizzle.js
* http://sizzlejs.com/
* Copyright 2010, The Dojo Foundation
* Released under the MIT, BSD, and GPL Licenses.
*
* Date: Sat Feb 13 22:33:48 2010 -0500
*/
(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o<i;o++)e(a[o],b,f?d.call(a[o],o,e(a[o],b)):d,j);return a}return i?
e(a[0],b):w}function J(){return(new Date).getTime()}function Y(){return false}function Z(){return true}function na(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function oa(a){var b,d=[],f=[],e=arguments,j,i,o,k,n,r;i=c.data(this,"events");if(!(a.liveFired===this||!i||!i.live||a.button&&a.type==="click")){a.liveFired=this;var u=i.live.slice(0);for(k=0;k<u.length;k++){i=u[k];i.origType.replace(O,"")===a.type?f.push(i.selector):u.splice(k--,1)}j=c(a.target).closest(f,a.currentTarget);n=0;for(r=
j.length;n<r;n++)for(k=0;k<u.length;k++){i=u[k];if(j[n].selector===i.selector){o=j[n].elem;f=null;if(i.preType==="mouseenter"||i.preType==="mouseleave")f=c(a.relatedTarget).closest(i.selector)[0];if(!f||f!==o)d.push({elem:o,handleObj:i})}}n=0;for(r=d.length;n<r;n++){j=d[n];a.currentTarget=j.elem;a.data=j.handleObj.data;a.handleObj=j.handleObj;if(j.handleObj.origHandler.apply(j.elem,e)===false){b=false;break}}return b}}function pa(a,b){return"live."+(a&&a!=="*"?a+".":"")+b.replace(/\./g,"`").replace(/ /g,
"&")}function qa(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function ra(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var f=c.data(a[d++]),e=c.data(this,f);if(f=f&&f.events){delete e.handle;e.events={};for(var j in f)for(var i in f[j])c.event.add(this,j,f[j][i],f[j][i].data)}}})}function sa(a,b,d){var f,e,j;b=b&&b[0]?b[0].ownerDocument||b[0]:s;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===s&&!ta.test(a[0])&&(c.support.checkClone||!ua.test(a[0]))){e=
true;if(j=c.fragments[a[0]])if(j!==1)f=j}if(!f){f=b.createDocumentFragment();c.clean(a,b,f,d)}if(e)c.fragments[a[0]]=j?f:1;return{fragment:f,cacheable:e}}function K(a,b){var d={};c.each(va.concat.apply([],va.slice(0,b)),function(){d[this]=a});return d}function wa(a){return"scrollTo"in a&&a.document?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var c=function(a,b){return new c.fn.init(a,b)},Ra=A.jQuery,Sa=A.$,s=A.document,T,Ta=/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/,
Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&&
(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this,
a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b===
"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this,
function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(j in e){i=a[j];o=e[j];if(a!==o)if(f&&o&&(c.isPlainObject(o)||c.isArray(o))){i=i&&(c.isPlainObject(i)||
c.isArray(i))?i:c.isArray(o)?[]:{};a[j]=c.extend(f,i,o)}else if(o!==w)a[j]=o}return a};c.extend({noConflict:function(a){A.$=Sa;if(a)A.jQuery=Ra;return c},isReady:false,ready:function(){if(!c.isReady){if(!s.body)return setTimeout(c.ready,13);c.isReady=true;if(Q){for(var a,b=0;a=Q[b++];)a.call(s,c);Q=null}c.fn.triggerHandler&&c(s).triggerHandler("ready")}},bindReady:function(){if(!xa){xa=true;if(s.readyState==="complete")return c.ready();if(s.addEventListener){s.addEventListener("DOMContentLoaded",
L,false);A.addEventListener("load",c.ready,false)}else if(s.attachEvent){s.attachEvent("onreadystatechange",L);A.attachEvent("onload",c.ready);var a=false;try{a=A.frameElement==null}catch(b){}s.documentElement.doScroll&&a&&ma()}}},isFunction:function(a){return $.call(a)==="[object Function]"},isArray:function(a){return $.call(a)==="[object Array]"},isPlainObject:function(a){if(!a||$.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!aa.call(a,"constructor")&&!aa.call(a.constructor.prototype,
"isPrototypeOf"))return false;var b;for(b in a);return b===w||aa.call(a,b)},isEmptyObject:function(a){for(var b in a)return false;return true},error:function(a){throw a;},parseJSON:function(a){if(typeof a!=="string"||!a)return null;a=c.trim(a);if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return A.JSON&&A.JSON.parse?A.JSON.parse(a):(new Function("return "+
a))();else c.error("Invalid JSON: "+a)},noop:function(){},globalEval:function(a){if(a&&Va.test(a)){var b=s.getElementsByTagName("head")[0]||s.documentElement,d=s.createElement("script");d.type="text/javascript";if(c.support.scriptEval)d.appendChild(s.createTextNode(a));else d.text=a;b.insertBefore(d,b.firstChild);b.removeChild(d)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){var f,e=0,j=a.length,i=j===w||c.isFunction(a);if(d)if(i)for(f in a){if(b.apply(a[f],
d)===false)break}else for(;e<j;){if(b.apply(a[e++],d)===false)break}else if(i)for(f in a){if(b.call(a[f],f,a[f])===false)break}else for(d=a[0];e<j&&b.call(d,e,d)!==false;d=a[++e]);return a},trim:function(a){return(a||"").replace(Wa,"")},makeArray:function(a,b){b=b||[];if(a!=null)a.length==null||typeof a==="string"||c.isFunction(a)||typeof a!=="function"&&a.setInterval?ba.call(b,a):c.merge(b,a);return b},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var d=0,f=b.length;d<f;d++)if(b[d]===
a)return d;return-1},merge:function(a,b){var d=a.length,f=0;if(typeof b.length==="number")for(var e=b.length;f<e;f++)a[d++]=b[f];else for(;b[f]!==w;)a[d++]=b[f++];a.length=d;return a},grep:function(a,b,d){for(var f=[],e=0,j=a.length;e<j;e++)!d!==!b(a[e],e)&&f.push(a[e]);return f},map:function(a,b,d){for(var f=[],e,j=0,i=a.length;j<i;j++){e=b(a[j],j,d);if(e!=null)f[f.length]=e}return f.concat.apply([],f)},guid:1,proxy:function(a,b,d){if(arguments.length===2)if(typeof b==="string"){d=a;a=d[b];b=w}else if(b&&
!c.isFunction(b)){d=b;b=w}if(!b&&a)b=function(){return a.apply(d||this,arguments)};if(a)b.guid=a.guid=a.guid||b.guid||c.guid++;return b},uaMatch:function(a){a=a.toLowerCase();a=/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version)?[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||!/compatible/.test(a)&&/(mozilla)(?:.*? rv:([\w.]+))?/.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}},browser:{}});P=c.uaMatch(P);if(P.browser){c.browser[P.browser]=true;c.browser.version=P.version}if(c.browser.webkit)c.browser.safari=
true;if(ya)c.inArray=function(a,b){return ya.call(b,a)};T=c(s);if(s.addEventListener)L=function(){s.removeEventListener("DOMContentLoaded",L,false);c.ready()};else if(s.attachEvent)L=function(){if(s.readyState==="complete"){s.detachEvent("onreadystatechange",L);c.ready()}};(function(){c.support={};var a=s.documentElement,b=s.createElement("script"),d=s.createElement("div"),f="script"+J();d.style.display="none";d.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected,
parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent=
false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n=
s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true,
applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando];
else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this,
a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===
w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i,
cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1)if(e.className){for(var j=" "+e.className+" ",
i=e.className,o=0,k=b.length;o<k;o++)if(j.indexOf(" "+b[o]+" ")<0)i+=" "+b[o];e.className=c.trim(i)}else e.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(k){var n=c(this);n.removeClass(a.call(this,k,n.attr("class")))});if(a&&typeof a==="string"||a===w)for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1&&e.className)if(a){for(var j=(" "+e.className+" ").replace(Aa," "),i=0,o=b.length;i<o;i++)j=j.replace(" "+b[i]+" ",
" ");e.className=c.trim(j)}else e.className=""}return this},toggleClass:function(a,b){var d=typeof a,f=typeof b==="boolean";if(c.isFunction(a))return this.each(function(e){var j=c(this);j.toggleClass(a.call(this,e,j.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var e,j=0,i=c(this),o=b,k=a.split(ca);e=k[j++];){o=f?o:!i.hasClass(e);i[o?"addClass":"removeClass"](e)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className=
this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(Aa," ").indexOf(a)>-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j<d;j++){var i=
e[j];if(i.selected){a=c(i).val();if(b)return a;f.push(a)}}return f}if(Ba.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Za,"")}return w}var o=c.isFunction(a);return this.each(function(k){var n=c(this),r=a;if(this.nodeType===1){if(o)r=a.call(this,k,n.val());if(typeof r==="number")r+="";if(c.isArray(r)&&Ba.test(this.type))this.checked=c.inArray(n.val(),r)>=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected=
c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");
a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g,
function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split(".");
k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a),
C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B<r.length;B++){u=r[B];if(d.guid===u.guid){if(i||k.test(u.namespace)){f==null&&r.splice(B--,1);n.remove&&n.remove.call(a,u)}if(f!=
null)break}}if(r.length===0||f!=null&&r.length===1){if(!n.teardown||n.teardown.call(a,o)===false)Ca(a,e,z.handle);delete C[e]}}else for(var B=0;B<r.length;B++){u=r[B];if(i||k.test(u.namespace)){c.event.remove(a,n,u.handler,B);r.splice(B--,1)}}}if(c.isEmptyObject(C)){if(b=z.handle)b.elem=null;delete z.events;delete z.handle;c.isEmptyObject(z)&&c.removeData(a)}}}}},trigger:function(a,b,d,f){var e=a.type||a;if(!f){a=typeof a==="object"?a[G]?a:c.extend(c.Event(e),a):c.Event(e);if(e.indexOf("!")>=0){a.type=
e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&&
f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;
if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e<j;e++){var i=d[e];if(b||f.test(i.namespace)){a.handler=i.handler;a.data=i.data;a.handleObj=i;i=i.handler.apply(this,arguments);if(i!==w){a.result=i;if(i===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
fix:function(a){if(a[G])return a;var b=a;a=c.Event(b);for(var d=this.props.length,f;d;){f=this.props[--d];a[f]=b[f]}if(!a.target)a.target=a.srcElement||s;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=s.documentElement;d=s.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(!a.which&&(a.charCode||a.charCode===0?a.charCode:a.keyCode))a.which=a.charCode||a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==w)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,a.origType,c.extend({},a,{handler:oa}))},remove:function(a){var b=true,d=a.origType.replace(O,"");c.each(c.data(this,
"events").live||[],function(){if(d===this.origType.replace(O,""))return b=false});b&&c.event.remove(this,a.origType,oa)}},beforeunload:{setup:function(a,b,d){if(this.setInterval)this.onbeforeunload=d;return false},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};var Ca=s.removeEventListener?function(a,b,d){a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=
a;this.type=a.type}else this.type=a;this.timeStamp=J();this[G]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=Z;var a=this.originalEvent;if(a){a.preventDefault&&a.preventDefault();a.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=Z;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z;this.stopPropagation()},isDefaultPrevented:Y,isPropagationStopped:Y,
isImmediatePropagationStopped:Y};var Da=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},Ea=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?Ea:Da,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?Ea:Da)}}});if(!c.support.submitBubbles)c.event.special.submit=
{setup:function(){if(this.nodeName.toLowerCase()!=="form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length)return na("submit",this,arguments)});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13)return na("submit",this,arguments)})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};
if(!c.support.changeBubbles){var da=/textarea|input|select/i,ea,Fa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",
e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,
"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a,
d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j<o;j++)c.event.add(this[j],d,i,f)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&
!a.preventDefault)for(var d in a)this.unbind(d,a[d]);else{d=0;for(var f=this.length;d<f;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,f){return this.live(b,d,f,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){a=c.Event(a);a.preventDefault();a.stopPropagation();c.event.trigger(a,b,this[0]);return a.result}},
toggle:function(a){for(var b=arguments,d=1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(f){var e=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,e+1);f.preventDefault();return b[e].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var Ga={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,f,e,j){var i,o=0,k,n,r=j||this.selector,
u=j?this:c(this.context);if(c.isFunction(f)){e=f;f=w}for(d=(d||"").split(" ");(i=d[o++])!=null;){j=O.exec(i);k="";if(j){k=j[0];i=i.replace(O,"")}if(i==="hover")d.push("mouseenter"+k,"mouseleave"+k);else{n=i;if(i==="focus"||i==="blur"){d.push(Ga[i]+k);i+=k}else i=(Ga[i]||i)+k;b==="live"?u.each(function(){c.event.add(this,pa(i,r),{data:f,selector:r,handler:e,origType:i,origHandler:e,preType:n})}):u.unbind(pa(i,r),e)}}return this}});c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),
function(a,b){c.fn[b]=function(d){return d?this.bind(b,d):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});A.attachEvent&&!A.addEventListener&&A.attachEvent("onunload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});(function(){function a(g){for(var h="",l,m=0;g[m];m++){l=g[m];if(l.nodeType===3||l.nodeType===4)h+=l.nodeValue;else if(l.nodeType!==8)h+=a(l.childNodes)}return h}function b(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];
if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1&&!p){t.sizcache=l;t.sizset=q}if(t.nodeName.toLowerCase()===h){y=t;break}t=t[g]}m[q]=y}}}function d(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1){if(!p){t.sizcache=l;t.sizset=q}if(typeof h!=="string"){if(t===h){y=true;break}}else if(k.filter(h,[t]).length>0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift();
t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D||
g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h<g.length;h++)g[h]===g[h-1]&&g.splice(h--,1)}return g};k.matches=function(g,h){return k(g,null,null,h)};k.find=function(g,h,l){var m,q;if(!g)return[];
for(var p=0,v=n.order.length;p<v;p++){var t=n.order[p];if(q=n.leftMatch[t].exec(g)){var y=q[1];q.splice(1,1);if(y.substr(y.length-1)!=="\\"){q[1]=(q[1]||"").replace(/\\/g,"");m=n.find[t](q,h,l);if(m!=null){g=g.replace(n.match[t],"");break}}}}m||(m=h.getElementsByTagName("*"));return{set:m,expr:g}};k.filter=function(g,h,l,m){for(var q=g,p=[],v=h,t,y,S=h&&h[0]&&x(h[0]);g&&h.length;){for(var H in n.filter)if((t=n.leftMatch[H].exec(g))!=null&&t[2]){var M=n.filter[H],I,D;D=t[1];y=false;t.splice(1,1);if(D.substr(D.length-
1)!=="\\"){if(v===p)p=[];if(n.preFilter[H])if(t=n.preFilter[H](t,v,l,p,m,S)){if(t===true)continue}else y=I=true;if(t)for(var U=0;(D=v[U])!=null;U++)if(D){I=M(D,t,U,v);var Ha=m^!!I;if(l&&I!=null)if(Ha)y=true;else v[U]=false;else if(Ha){p.push(D);y=true}}if(I!==w){l||(v=p);g=g.replace(n.match[H],"");if(!y)return[];break}}}if(g===q)if(y==null)k.error(g);else break;q=g}return v};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var n=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
CLASS:/\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},
relative:{"+":function(g,h){var l=typeof h==="string",m=l&&!/\W/.test(h);l=l&&!m;if(m)h=h.toLowerCase();m=0;for(var q=g.length,p;m<q;m++)if(p=g[m]){for(;(p=p.previousSibling)&&p.nodeType!==1;);g[m]=l||p&&p.nodeName.toLowerCase()===h?p||false:p===h}l&&k.filter(h,g,true)},">":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m<q;m++){var p=g[m];if(p){l=p.parentNode;g[m]=l.nodeName.toLowerCase()===h?l:false}}}else{m=0;for(q=g.length;m<q;m++)if(p=g[m])g[m]=
l?p.parentNode:p.parentNode===h;l&&k.filter(h,g,true)}},"":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("parentNode",h,m,g,p,l)},"~":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("previousSibling",h,m,g,p,l)}},find:{ID:function(g,h,l){if(typeof h.getElementById!=="undefined"&&!l)return(g=h.getElementById(g[1]))?[g]:[]},NAME:function(g,h){if(typeof h.getElementsByName!=="undefined"){var l=[];
h=h.getElementsByName(g[1]);for(var m=0,q=h.length;m<q;m++)h[m].getAttribute("name")===g[1]&&l.push(h[m]);return l.length===0?null:l}},TAG:function(g,h){return h.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,h,l,m,q,p){g=" "+g[1].replace(/\\/g,"")+" ";if(p)return g;p=0;for(var v;(v=h[p])!=null;p++)if(v)if(q^(v.className&&(" "+v.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},
CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m,
g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},
text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},
setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return h<l[3]-0},gt:function(g,h,l){return h>l[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h=
h[3];l=0;for(m=h.length;l<m;l++)if(h[l]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+q)},CHILD:function(g,h){var l=h[1],m=g;switch(l){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(l==="first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":l=h[2];var q=h[3];if(l===1&&q===0)return true;h=h[0];var p=g.parentNode;if(p&&(p.sizcache!==h||!g.nodeIndex)){var v=0;for(m=p.firstChild;m;m=
m.nextSibling)if(m.nodeType===1)m.nodeIndex=++v;p.sizcache=h}g=g.nodeIndex-q;return l===0?g===0:g%l===0&&g/l>=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m===
"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g,
h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l<m;l++)h.push(g[l]);else for(l=0;g[l];l++)h.push(g[l]);return h}}var B;if(s.documentElement.compareDocumentPosition)B=function(g,h){if(!g.compareDocumentPosition||
!h.compareDocumentPosition){if(g==h)i=true;return g.compareDocumentPosition?-1:1}g=g.compareDocumentPosition(h)&4?-1:g===h?0:1;if(g===0)i=true;return g};else if("sourceIndex"in s.documentElement)B=function(g,h){if(!g.sourceIndex||!h.sourceIndex){if(g==h)i=true;return g.sourceIndex?-1:1}g=g.sourceIndex-h.sourceIndex;if(g===0)i=true;return g};else if(s.createRange)B=function(g,h){if(!g.ownerDocument||!h.ownerDocument){if(g==h)i=true;return g.ownerDocument?-1:1}var l=g.ownerDocument.createRange(),m=
h.ownerDocument.createRange();l.setStart(g,0);l.setEnd(g,0);m.setStart(h,0);m.setEnd(h,0);g=l.compareBoundaryPoints(Range.START_TO_END,m);if(g===0)i=true;return g};(function(){var g=s.createElement("div"),h="script"+(new Date).getTime();g.innerHTML="<a name='"+h+"'/>";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&&
q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML="<a href='#'></a>";
if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="<p class='TEST'></p>";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}();
(function(){var g=s.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}:
function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q<p;q++)k(g,h[q],l);return k.filter(m,l)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=a;c.isXMLDoc=x;c.contains=E})();var eb=/Until$/,fb=/^(?:parents|prevUntil|prevAll)/,
gb=/,/;R=Array.prototype.slice;var Ia=function(a,b,d){if(c.isFunction(b))return c.grep(a,function(e,j){return!!b.call(e,j,e)===d});else if(b.nodeType)return c.grep(a,function(e){return e===b===d});else if(typeof b==="string"){var f=c.grep(a,function(e){return e.nodeType===1});if(Ua.test(b))return c.filter(b,f,!d);else b=c.filter(b,f)}return c.grep(a,function(e){return c.inArray(e,b)>=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f<e;f++){d=b.length;
c.find(a,this[f],b);if(f>0)for(var j=d;j<b.length;j++)for(var i=0;i<d;i++)if(b[i]===b[j]){b.splice(j--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,f=b.length;d<f;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(Ia(this,a,false),"not",a)},filter:function(a){return this.pushStack(Ia(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j=
{},i;if(f&&a.length){e=0;for(var o=a.length;e<o;e++){i=a[e];j[i]||(j[i]=c.expr.match.POS.test(i)?c(i,b||this.context):i)}for(;f&&f.ownerDocument&&f!==b;){for(i in j){e=j[i];if(e.jquery?e.index(f)>-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a===
"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",
d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?
a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType===
1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/<tbody/i,jb=/<|&#?\w+;/,ta=/<script|<object|<embed|<option|<style/i,ua=/checked\s*(?:[^=]|=\s*.checked.)/i,Ma=function(a,b,d){return hb.test(d)?
a:b+"></"+d+">"},F={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=
c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},
prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,
this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);
return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja,
""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(f){this.empty().append(a)}}else c.isFunction(a)?this.each(function(e){var j=c(this),i=j.html();j.empty().append(function(){return a.call(this,e,i)})}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&
this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=c(this),f=d.html();d.replaceWith(a.call(this,b,f))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){function f(u){return c.nodeName(u,"table")?u.getElementsByTagName("tbody")[0]||
u.appendChild(u.ownerDocument.createElement("tbody")):u}var e,j,i=a[0],o=[],k;if(!c.support.checkClone&&arguments.length===3&&typeof i==="string"&&ua.test(i))return this.each(function(){c(this).domManip(a,b,d,true)});if(c.isFunction(i))return this.each(function(u){var z=c(this);a[0]=i.call(this,u,b?z.html():w);z.domManip(a,b,d)});if(this[0]){e=i&&i.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:sa(a,this,o);k=e.fragment;if(j=k.childNodes.length===
1?(k=k.firstChild):k.firstChild){b=b&&c.nodeName(j,"tr");for(var n=0,r=this.length;n<r;n++)d.call(b?f(this[n],j):this[n],n>0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]);
return this}else{e=0;for(var j=d.length;e<j;e++){var i=(e>0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["",
""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]==="<table>"&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e=
c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]?
c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja=
function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter=
Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a,
"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f=
a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=
a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=/<script(.|\s)*?\/script>/gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!==
"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("<div />").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this},
serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),
function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,
global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&&
e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)?
"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache===
false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B=
false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since",
c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E||
d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x);
g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===
1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b===
"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional;
if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");
this[a].style.display=d||"";if(c.css(this[a],"display")==="none"){d=this[a].nodeName;var f;if(la[d])f=la[d];else{var e=c("<"+d+" />").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b){if(a||a===0)return this.animate(K("hide",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");!d&&d!=="none"&&c.data(this[a],
"olddisplay",c.css(this[a],"display"))}a=0;for(b=this.length;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b){var d=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||d?this.each(function(){var f=d?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(K("toggle",3),a,b);return this},fadeTo:function(a,b,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d)},
animate:function(a,b,d,f){var e=c.speed(b,d,f);if(c.isEmptyObject(a))return this.each(e.complete);return this[e.queue===false?"each":"queue"](function(){var j=c.extend({},e),i,o=this.nodeType===1&&c(this).is(":hidden"),k=this;for(i in a){var n=i.replace(ia,ja);if(i!==n){a[n]=a[i];delete a[i];i=n}if(a[i]==="hide"&&o||a[i]==="show"&&!o)return j.complete.call(this);if((i==="height"||i==="width")&&this.style){j.display=c.css(this,"display");j.overflow=this.style.overflow}if(c.isArray(a[i])){(j.specialEasing=
j.specialEasing||{})[i]=a[i][1];a[i]=a[i][0]}}if(j.overflow!=null)this.style.overflow="hidden";j.curAnim=c.extend({},a);c.each(a,function(r,u){var z=new c.fx(k,j,r);if(Ab.test(u))z[u==="toggle"?o?"show":"hide":u](a);else{var C=Bb.exec(u),B=z.cur(true)||0;if(C){u=parseFloat(C[2]);var E=C[3]||"px";if(E!=="px"){k.style[r]=(u||1)+E;B=(u||1)/z.cur(true)*B;k.style[r]=B+E}if(C[1])u=(C[1]==="-="?-1:1)*u+B;z.custom(B,u,E)}else z.custom(B,u,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);
this.each(function(){for(var f=d.length-1;f>=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration===
"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||
c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;
this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=
this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem,
e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||
c.fx.stop()},stop:function(){clearInterval(W);W=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===b.elem}).length};c.fn.offset="getBoundingClientRect"in s.documentElement?
function(a){var b=this[0];if(a)return this.each(function(e){c.offset.setOffset(this,a,e)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);var d=b.getBoundingClientRect(),f=b.ownerDocument;b=f.body;f=f.documentElement;return{top:d.top+(self.pageYOffset||c.support.boxModel&&f.scrollTop||b.scrollTop)-(f.clientTop||b.clientTop||0),left:d.left+(self.pageXOffset||c.support.boxModel&&f.scrollLeft||b.scrollLeft)-(f.clientLeft||b.clientLeft||0)}}:function(a){var b=
this[0];if(a)return this.each(function(r){c.offset.setOffset(this,a,r)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,f=b,e=b.ownerDocument,j,i=e.documentElement,o=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;for(var k=b.offsetTop,n=b.offsetLeft;(b=b.parentNode)&&b!==o&&b!==i;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;j=e?e.getComputedStyle(b,null):b.currentStyle;
k-=b.scrollTop;n-=b.scrollLeft;if(b===d){k+=b.offsetTop;n+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(b.nodeName))){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=d;d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&j.overflow!=="visible"){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=j}if(f.position==="relative"||f.position==="static"){k+=o.offsetTop;n+=o.offsetLeft}if(c.offset.supportsFixedPosition&&
f.position==="fixed"){k+=Math.max(i.scrollTop,o.scrollTop);n+=Math.max(i.scrollLeft,o.scrollLeft)}return{top:k,left:n}};c.offset={initialize:function(){var a=s.body,b=s.createElement("div"),d,f,e,j=parseFloat(c.curCSS(a,"marginTop",true))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";
a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b);
c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a,
d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top-
f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset":
"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in
e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window);
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/.
log4j.rootCategory=INFO, CONSOLE
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d %p [%c] (%x:%t) - <%m>%n
#log4j.category.org.springframework.security=DEBUG
#log4j.category.org.springframework.web=DEBUG
log4j.rootCategory=INFO, CONSOLE
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d %p [%c] (%x:%t) - <%m>%n
log4j.category.org.springframework.security=DEBUG
log4j.category.org.openid4java=DEBUG
log4j.category.org.cloudfoundry.identity=DEBUG
log4j.rootCategory=INFO, CONSOLE
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d %p [%c] (%x:%t) - <%m>%n
log4j.category.org.springframework.security=DEBUG
log4j.category.org.cloudfoundry.identity=DEBUG
log4j.category.org.openid4java=DEBUG
log4j.rootCategory=INFO, CONSOLE
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d %p [%c] (%x:%t) - <%m>%n
log4j.category.org.springframework.security=DEBUG
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<link type="text/css" rel="stylesheet" href="<c:url value="/resources/style.css"/>"/>
</head>
<body>
<h1>OpenID Sample Home Page</h1>
<p>
You are logged out.
</p>
<ul>
<li><a href="photos">Photos</a></li>
<li><a href="<c:url value="/"/>">Home</a></li>
</ul>
</body>
</html>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<link type="text/css" rel="stylesheet" href="<c:url value="/resources/style.css"/>"/>
</head>
<body>
<h1>OpenID Sample Home Page</h1>
<p>
You are logged out.
</p>
<ul>
<li><a href="<c:url value="/"/>">Home</a></li>
</ul>
</body>
</html>
<%@ page
import="org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter"%>
<%@ taglib prefix="authz"
uri="http://www.springframework.org/security/tags"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/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>Authorization Server Login</title>
<link type="text/css" rel="stylesheet"
href="<c:url value="/resources/style.css"/>" />
</head>
<body>
<h1>Authentication</h1>
<div id="content">
<%
if (session.getAttribute(AbstractAuthenticationProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY) != null) {
%>
<div class="error">
<h2>Woops!</h2>
<p>
Your login attempt was not successful. (<%=((Exception) session
.getAttribute(AbstractAuthenticationProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY))
.getMessage()%>)
</p>
</div>
<%
}
%>
<c:remove scope="session" var="SPRING_SECURITY_LAST_EXCEPTION" />
<authz:authorize ifNotGranted="ROLE_USER">
<h2>Login</h2>
<p>
You need to authenticate.
</p>
<p>Enter your user name and password.</p>
<form id="loginForm" name="loginForm"
action="<c:url value="/login.do"/>" method="POST">
<p>
<label>Username: <input type='text' name='username'
value="${username}" /> </label>
</p>
<p>
<label>Password: <input type='password' name='password'
value="" /> </label>
</p>
<p>
<input name="login" value="Login" type="submit" />
</p>
</form>
</authz:authorize>
</div>
<div id="footer">Demo only</div>
</body>
</html>
<%@ page
import="org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<link type="text/css" rel="stylesheet" href="<c:url value="/resources/style.css"/>"/>
</head>
<body>
<h1>OpenID Sample Error Page</h1>
<p>
There was a problem logging you in. Don't panic.
</p>
<ul>
<li><a href="photos">Photos</a></li>
<li><a href="<c:url value="/"/>">Home</a></li>
</ul>
<%
if (session.getAttribute(AbstractAuthenticationProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY) != null) {
%>
<div class="error">
<p>
<%= session
.getAttribute(AbstractAuthenticationProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY) %>
<% ((Exception) session
.getAttribute(AbstractAuthenticationProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY)).printStackTrace();%>
</p>
</div>
<%
}
%>
</body>
</html>
<%@ page
import="org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<link type="text/css" rel="stylesheet" href="<c:url value="/resources/style.css"/>"/>
</head>
<body>
<h1>OpenID Sample Error Page</h1>
<p>
There was a problem logging you in. Don't panic.
</p>
<ul>
<li><a href="<c:url value="/"/>">Home</a></li>
</ul>
<%
if (session.getAttribute(AbstractAuthenticationProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY) != null) {
%>
<div class="error">
<p>
<%= session
.getAttribute(AbstractAuthenticationProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY) %>
<% ((Exception) session
.getAttribute(AbstractAuthenticationProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY)).printStackTrace();%>
</p>
</div>
<%
}
%>
</body>
</html>
/*
* 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.cloudfoundry.identity.app.web;
import java.security.Principal;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class LoginController {
private String openidProviderUrl;
public void setOpenidProviderUrl(String openidProviderUrl) {
this.openidProviderUrl = openidProviderUrl;
}
public String getLoginUrl() {
return "/login?action=verify&openid_identifier="+openidProviderUrl;
}
@RequestMapping("/home")
public String home(Model model, Principal principal) {
model.addAttribute("principal", principal);
return "home";
}
}
/*
* 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.cloudfoundry.identity.app.web;
import java.security.Principal;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class LoginController {
private String openidProviderUrl;
public void setOpenidProviderUrl(String openidProviderUrl) {
this.openidProviderUrl = openidProviderUrl;
}
public String getLoginUrl() {
return "/login?action=verify&openid_identifier="+openidProviderUrl;
}
@RequestMapping("/home")
public String home(Model model, Principal principal) {
model.addAttribute("principal", principal);
return "home";
}
}
/*
* Copyright 2009-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.cloudfoundry.identity.app.web;
import java.util.Map;
import org.springframework.context.expression.MapAccessor;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
public class MapWrapper {
private final SpelExpressionParser parser;
private final StandardEvaluationContext context;
private Object target;
public MapWrapper(Object target) throws Exception {
this.target = target;
context = new StandardEvaluationContext();
context.addPropertyAccessor(new MapAccessor());
parser = new SpelExpressionParser();
}
@SuppressWarnings("unchecked")
public Map<String, Object> getMap() {
return (Map<String, Object>) target;
}
public Object get(String expression) throws Exception {
return get(expression, Object.class);
}
public <T> T get(String expression, Class<T> type) throws Exception {
return parser.parseExpression(expression).getValue(context, target,
type);
}
@Override
public String toString() {
return target.toString();
}
}
<%@ page
import="org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter"%>
<%@ taglib prefix="authz"
uri="http://www.springframework.org/security/tags"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/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>OpenID Authorization</title>
<link type="text/css" rel="stylesheet"
href="<c:url value="/resources/style.css"/>" />
</head>
<body>
<h1>OpenID Attribute Authorization</h1>
<div id="content">
<p>
The site
<pre>${openid.site}</pre>
is asking to retrieve your email and fullname from the OpenID
provider:
<pre>${openid.identity}</pre>
</p>
<form id="loginForm" name="loginForm"
action="<c:url value="/openid/authorize"/>" method="POST">
<p>
<input name="approve" value="Approve" type="submit" /> <input
name="deny" value="Deny" type="submit" />
</p>
</form>
</div>
<div id="footer">Demo only</div>
</body>
</html>
/*
* 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.cloudfoundry.identity.uaa.web;
import java.security.Principal;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import org.cloudfoundry.identity.uaa.web.OpenIdProviderController.Openid;
import org.openid4java.association.AssociationException;
import org.openid4java.message.AuthRequest;
import org.openid4java.message.AuthSuccess;
import org.openid4java.message.Message;
import org.openid4java.message.MessageException;
import org.openid4java.message.MessageExtension;
import org.openid4java.message.Parameter;
import org.openid4java.message.ParameterList;
import org.openid4java.message.ax.AxMessage;
import org.openid4java.message.ax.FetchRequest;
import org.openid4java.message.ax.FetchResponse;
import org.openid4java.server.ServerException;
import org.openid4java.server.ServerManager;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ModelAttribute;
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.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.view.RedirectView;
/**
* @author Dave Syer
*
*/
@Controller
@SessionAttributes(types = Openid.class)
public class OpenIdProviderController {
private ServerManager manager;
public void setServerManager(ServerManager manager) {
this.manager = manager;
}
@ModelAttribute
public Openid getOpenid() {
return new Openid();
}
@ModelAttribute
public ParameterList getParameterList(HttpServletRequest request) {
ParameterList list = new ParameterList(request.getParameterMap());
return list;
}
// TODO: provide user-friendly HTML output as well
@RequestMapping("/openid")
public ResponseEntity<String> xrdsDiscovery() {
MultiValueMap<String, String> headers = new HttpHeaders();
headers.set("Content-Type", "application/xrds+xml");
return new ResponseEntity<String>(String.format(XRDS_TEMPLATE, manager.getOPEndpointUrl()), headers, HttpStatus.OK);
}
// TODO: provide user-friendly HTML output as well
@RequestMapping("/openid/users/{username}")
public ResponseEntity<String> xrdsWithUsername(@PathVariable String username) {
MultiValueMap<String, String> headers = new HttpHeaders();
headers.set("Content-Type", "application/xrds+xml");
return new ResponseEntity<String>(String.format(XRDS_TEMPLATE, manager.getOPEndpointUrl() + "/users/"
+ username), headers, HttpStatus.OK);
}
@RequestMapping(value = "/openid/provider", params = "openid.mode=associate")
@ResponseBody
public String associate(@ModelAttribute Openid openid, @ModelAttribute ParameterList parameterList) {
openid.getParameterList().addParams(parameterList);
parameterList = openid.getParameterList();
return manager.associationResponse(openid.getParameterList()).keyValueFormEncoding();
}
@RequestMapping(value = "/openid/provider", params = "openid.mode=check_authentication")
@ResponseBody
public String checkAuthentication(@ModelAttribute ParameterList parameterList) {
Message responseMessage = manager.verify(parameterList);
// This is the back channel (so the session is irrelevant). The response
// has to be this precise text.
return responseMessage.keyValueFormEncoding();
}
@RequestMapping(value = "/openid/provider", params = "openid.mode=checkid_setup")
public View checkSetup(@ModelAttribute Openid openid, @ModelAttribute ParameterList parameterList) {
openid.getParameterList().addParams(parameterList);
return check(openid);
}
@RequestMapping(value = "/openid/provider", params = "openid.mode=checkid_immediate")
public View checkImmediate(@ModelAttribute Openid openid, @ModelAttribute ParameterList parameterList) {
openid.getParameterList().addParams(parameterList);
return check(openid);
}
// TODO: deal with openid.mode=cancel
@RequestMapping(value = "/openid/complete")
public View complete(@ModelAttribute Openid openid, @ModelAttribute ParameterList parameterList,
SessionStatus status) throws ServletException, MessageException, ServerException, AssociationException {
openid.getParameterList().addParams(parameterList);
parameterList = openid.getParameterList();
String mode = openid.getMode();
if (mode != null && mode.startsWith("checkid_")) {
// Remove the parameter list so this provider can accept requests
// from elsewhere
status.setComplete();
boolean authenticatedAndApproved = openid.isApproved();
String userSelectedClaimedId = openid.getClaimedIdentity();
String userSelectedId = openid.getIdentity();
// TODO: something sensible if the user chose a different claimed_id
// than the one in request
Message response = manager.authResponse(parameterList, userSelectedId, userSelectedClaimedId,
authenticatedAndApproved, false);
// Sign after we added extensions.
if (response instanceof AuthSuccess) {
Map<String, String> attributes = openid.getAttributes();
if (!attributes.isEmpty()) {
// --- process extensions
AuthRequest authReq = AuthRequest.createAuthRequest(parameterList, manager.getRealmVerifier());
if (authReq.hasExtension(AxMessage.OPENID_NS_AX)) {
MessageExtension ext = authReq.getExtension(AxMessage.OPENID_NS_AX);
if (ext instanceof FetchRequest) {
FetchRequest fetchReq = (FetchRequest) ext;
Map<String, String> userDataExt = new HashMap<String, String>();
FetchResponse fetchResp = FetchResponse.createFetchResponse(fetchReq, userDataExt);
@SuppressWarnings("unchecked")
Map<String, String> required = fetchReq.getAttributes(true);
for (String key : required.keySet()) {
if (attributes.containsKey(key)) {
fetchResp.addAttribute(key, required.get(key), attributes.get(key));
}
else {
throw new BadCredentialsException("Required OpenID attribute (" + key
+ ") not found.");
}
}
@SuppressWarnings("unchecked")
Map<String, String> optional = fetchReq.getAttributes(false);
for (String key : optional.keySet()) {
if (attributes.containsKey(key)) {
fetchResp.addAttribute(key, optional.get(key), attributes.get(key));
}
}
response.addExtension(fetchResp);
}
else { // if (ext instanceof StoreRequest)
throw new UnsupportedOperationException("Only fetch request is supported");
}
}
}
// Sign the auth success message.
manager.sign((AuthSuccess) response);
// GET HTTP-redirect to the return_to URL
return new RedirectView(response.getDestinationUrl(true), false);
}
// TODO: this is what happens with openid.mode=cancel
throw new AccessDeniedException("OpenID authentication failed (" + response.wwwFormEncoding() + ")");
}
throw new MissingServletRequestParameterException("openid.mode", "string");
}
private View check(Openid openid) {
boolean authenticatedAndApproved = openid.isApproved();
if (!authenticatedAndApproved) {
return new RedirectView("/openid/authorize", true);
}
// TODO: don't do this, it's dumb.
throw new InsufficientAuthenticationException("Not yet approved");
}
@RequestMapping(value = "/openid/authorize", method = RequestMethod.GET)
public String authorize(@ModelAttribute Openid openid, Model model, Principal user) {
model.addAttribute("openid", openid);
model.addAttribute("user", user);
return "openid_authorize";
}
@RequestMapping(value = "/openid/authorize", method = RequestMethod.POST)
public View authorize(@ModelAttribute Openid openid, Principal user,
@RequestParam(required = false) String approve, @RequestParam(required = false) String deny) {
// TODO: if approved is false you get openid.mode=cancel
openid.setApproved(approve != null && deny == null);
String name = user.getName();
if (name != null && name.contains("@")) {
name = name.substring(0, name.indexOf("@"));
name = name.replace(".", " ");
}
String email = user.getName();
if (email != null && !email.contains("@")) {
email = email + "@test.org";
}
if (user instanceof UsernamePasswordAuthenticationToken) {
if (((UsernamePasswordAuthenticationToken) user).getDetails() instanceof Map) {
@SuppressWarnings("unchecked")
Map<String, String> details = (Map<String, String>) ((UsernamePasswordAuthenticationToken) user)
.getDetails();
openid.getAttributes().putAll(details);
}
}
openid.getAttributes().put("email", email);
openid.getAttributes().put("fullname", name);
openid.setClaimedIdentity(openid.getIdentity() + "/users/" + name);
return new RedirectView("/openid/complete", true);
}
private static String XRDS_TEMPLATE = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" //
+ "<xrds:XRDS xmlns:xrds=\"xri://$xrds\" xmlns:openid=\"http://openid.net/xmlns/1.0\" xmlns=\"xri://$xrd*($v*2.0)\">" //
+ "<XRD><Service priority=\"0\">" //
+ "<Type>http://openid.net/signon/1.0</Type>" //
+ "<URI>%s</URI>" //
+ "</Service></XRD>" //
+ "</xrds:XRDS>";;
public static class Openid {
private boolean approved = false;
private Map<String, String> attributes = new HashMap<String, String>();
private ParameterList list = new ParameterList();
public ParameterList getParameterList() {
Map<String, String> map = new HashMap<String, String>();
list.addParams(new ParameterList(map));
return list;
}
public Map<String, String> getAttributes() {
return attributes;
}
public String getSite() {
return list.getParameterValue("openid.return_to") != null ? list.getParameterValue("openid.return_to")
: list.getParameterValue("openid.realm");
}
public String getMode() {
return list.getParameterValue("openid.mode");
}
public String getClaimedIdentity() {
return list.getParameterValue("openid.claimed_id");
}
public void setClaimedIdentity(String value) {
list.set(new Parameter("openid.claimed_id", value));
}
public String getIdentity() {
return list.getParameterValue("openid.identity");
}
public boolean isApproved() {
return approved;
}
public void setApproved(boolean approved) {
this.approved = approved;
}
@Override
public String toString() {
return list.toString();
}
}
}
package org.cloudfoundry.identity.api.web.mvc;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.Collection;
import java.util.Map;
import org.cloudfoundry.identity.api.PhotoInfo;
import org.cloudfoundry.identity.api.PhotoService;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* Controller for a specific photo.
*
* @author Ryan Heaton
* @author Dave Syer
*/
@Controller
public class PhotoController {
private PhotoService photoService;
@RequestMapping("/photos/{id}")
public ResponseEntity<byte[]> getPhoto(@PathVariable("id") String id) throws Exception {
InputStream photo = photoService.loadPhoto(id);
if (photo == null) {
return new ResponseEntity<byte[]>(HttpStatus.NOT_FOUND);
} else {
ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
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.setContentType(MediaType.IMAGE_JPEG);
return new ResponseEntity<byte[]>(out.toByteArray(), headers, HttpStatus.OK);
}
}
@RequestMapping("/photos")
public String list(Map<String,Collection<PhotoInfo>> model) {
model.put("photos", photoService.getPhotosForCurrentUser());
return "photos";
}
public void setPhotoService(PhotoService photoService) {
this.photoService = photoService;
}
}
/*
* 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.cloudfoundry.identity.app.web;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
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.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestOperations;
@Controller
public class PhotoController {
private RestOperations restTemplate;
private String photoListUrl;
private String photoUrlPattern;
private String photoUrlPassthruPattern;
public void setPhotoUrlPassthruPattern(String photoUrlPassthruPattern) {
this.photoUrlPassthruPattern = photoUrlPassthruPattern;
}
public void setPhotoListUrl(String photoListUrl) {
this.photoListUrl = photoListUrl;
}
public void setPhotoUrlPattern(String photoUrlPattern) {
this.photoUrlPattern = photoUrlPattern;
}
public void setRestTemplate(RestOperations restTemplate) {
this.restTemplate = restTemplate;
}
@RequestMapping("/photos")
public String photos(Model model) {
List<String> photos = new ArrayList<String>();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
HttpEntity<?> request = new HttpEntity<String>("", headers);
@SuppressWarnings("unchecked")
Map<String, List<Map<String, String>>> result = (Map<String, List<Map<String, String>>>) restTemplate.exchange(photoListUrl, HttpMethod.GET, request , Map.class).getBody();
for (Map<String,String> map : result.get("photos")) {
photos.add(String.format(photoUrlPattern, map.get("id")));
}
model.addAttribute("photos", photos);
return "photos";
}
@RequestMapping("/photos/{id}")
@ResponseBody
public ResponseEntity<byte[]> photo(@PathVariable String id) {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.IMAGE_JPEG));
HttpEntity<?> request = new HttpEntity<String>("", headers);
byte[] result = restTemplate.exchange(String.format(photoUrlPassthruPattern, id), HttpMethod.GET, request , byte[].class).getBody();
headers.setContentType(MediaType.IMAGE_JPEG);
return new ResponseEntity<byte[]>(result, headers, HttpStatus.OK);
}
}
/*
* 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.cloudfoundry.identity.api;
/**
* 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;
}
}
/*
* 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.cloudfoundry.identity.app.web;
import java.util.List;
import java.util.Map;
import org.codehaus.jackson.map.ObjectMapper;
import org.junit.Test;
/**
* @author Dave Syer
*
*/
public class PhotoInfoTests {
private String photos = "{\"photos\":[{\"name\":\"photo1.jpg\",\"id\":\"1\",\"userId\":\"marissa\",\"resourceURL\":\"/org/springframework/security/oauth/examples/api/impl/resources/photo1.jpg\"},{\"name\":\"photo3.jpg\",\"id\":\"3\",\"userId\":\"marissa\",\"resourceURL\":\"/org/springframework/security/oauth/examples/api/impl/resources/photo3.jpg\"},{\"name\":\"photo5.jpg\",\"id\":\"5\",\"userId\":\"marissa\",\"resourceURL\":\"/org/springframework/security/oauth/examples/api/impl/resources/photo5.jpg\"}]}";
@SuppressWarnings("rawtypes")
@Test
public void testSerialization() throws Exception {
ObjectMapper mapper = new ObjectMapper();
@SuppressWarnings("unchecked")
Map<String,Object> map = mapper.readValue(photos, Map.class);
System.err.println(((Map)((List)map.get("photos")).get(0)).get("id").getClass());
}
}
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<html>
<head>
<link type="text/css" rel="stylesheet" href="<c:url value="/resources/style.css"/>"/>
</head>
<body>
<h1>OpenID Sample Photos</h1>
Your photos:
<ul id="picturelist">
<c:forEach var="photo" items="${photos}">
<li><img src="<c:url value="${photo}"/>"/></li>
</c:forEach>
</ul>
<ul>
<li><a href="photos">Photos</a></li>
<li><a href="<c:url value="/"/>">Home</a></li>
<li><a href="j_spring_security_logout">Logout</a></li>
</ul>
</body>
</html>
package org.cloudfoundry.identity.api;
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();
/**
* Load a photo by id.
*
* @param id The id of the photo.
* @return The photo that was read.
*/
InputStream loadPhoto(String id);
}
package org.cloudfoundry.identity.api.service;
import org.cloudfoundry.identity.api.PhotoInfo;
import org.cloudfoundry.identity.api.PhotoService;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.authentication.BadCredentialsException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* Basic implementation for the photo service.
*
* @author Ryan Heaton
*/
public class PhotoServiceImpl implements PhotoService {
private List<PhotoInfo> photos;
public Collection<PhotoInfo> getPhotosForCurrentUser() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication.getPrincipal() instanceof UserDetails) {
UserDetails details = (UserDetails) authentication.getPrincipal();
String username = details.getUsername();
ArrayList<PhotoInfo> infos = new ArrayList<PhotoInfo>();
for (PhotoInfo info : getPhotos()) {
if (username.equals(info.getUserId())) {
infos.add(info);
}
}
return infos;
}
else {
throw new BadCredentialsException("Bad credentials: not a username/password authentication.");
}
}
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.cloudfoundry.runtime</groupId>
<artifactId>parent</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<artifactId>api</artifactId>
<packaging>war</packaging>
<name>api</name>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<warSourceDirectory>src/main/webapp</warSourceDirectory>
<webResources>
<resource>
<directory>src/main/webapp</directory>
<filtering>true</filtering>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</webResources>
</configuration>
</plugin>
<plugin>
<!-- skip unit test run, tests to be executed during integration-test -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
<executions>
<execution>
<id>surefire-it</id>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<skip>${skipTests}</skip>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<configuration>
<scanIntervalSeconds>10</scanIntervalSeconds>
<stopKey>api</stopKey>
<stopPort>9999</stopPort>
</configuration>
<executions>
<execution>
<id>start-jetty</id>
<phase>pre-integration-test</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<scanIntervalSeconds>0</scanIntervalSeconds>
<daemon>true</daemon>
</configuration>
</execution>
<execution>
<id>stop-jetty</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<!--skip deploy (this is just a test module) -->
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>${spring.security.oauth.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</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-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</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.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</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>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>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.sourceforge.htmlunit</groupId>
<artifactId>htmlunit</artifactId>
<version>2.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb-j5</artifactId>
<version>2.0.0</version>
<scope>runtime</scope>
</dependency>
</dependencies>
<!-- <profiles> <profile> <id>gae</id> <dependencies> <dependency> <groupId>com.google.appengine</groupId>
<artifactId>api</dependency>
</dependencies> </profile> </profiles> -->
</project>
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.cloudfoundry.runtime</groupId>
<artifactId>parent</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<artifactId>app</artifactId>
<packaging>war</packaging>
<name>app</name>
<dependencies>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-openid</artifactId>
<version>${spring.security.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.8.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.5.8</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</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-beans</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-tx</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-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>${spring.security.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>${spring.security.oauth.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>${spring.security.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring.security.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.8.3</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.5.8</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.5.8</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.1.1</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</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.cloudfoundry.runtime</groupId>
<artifactId>parent</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<artifactId>auth</artifactId>
<packaging>war</packaging>
<name>auth</name>
<profiles>
<profile>
<id>rundb</id>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.1</version>
<configuration>
<mainClass>org.hsqldb.Server</mainClass>
<classpathScope>runtime</classpathScope>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<warSourceDirectory>src/main/webapp</warSourceDirectory>
<webResources>
<resource>
<directory>src/main/webapp</directory>
<filtering>true</filtering>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</webResources>
</configuration>
</plugin>
<plugin>
<!-- skip unit test run, tests to be executed during integration-test -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
<executions>
<execution>
<id>surefire-it</id>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<skip>${skipTests}</skip>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<configuration>
<scanIntervalSeconds>10</scanIntervalSeconds>
<stopKey>auth</stopKey>
<stopPort>9999</stopPort>
</configuration>
<executions>
<execution>
<id>start-jetty</id>
<phase>pre-integration-test</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<scanIntervalSeconds>0</scanIntervalSeconds>
<daemon>true</daemon>
</configuration>
</execution>
<execution>
<id>stop-jetty</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<!--skip deploy (this is just a test module) -->
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>${spring.security.oauth.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-tx</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.security</groupId>
<artifactId>spring-security-ldap</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-openid</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.5.8</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.5.8</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.8.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb-j5</artifactId>
<version>2.0.0</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.directory.server</groupId>
<artifactId>apacheds-protocol-ldap</artifactId>
<version>1.5.5</version>
</dependency>
<dependency>
<groupId>org.apache.directory.shared</groupId>
<artifactId>shared-ldap</artifactId>
<version>0.9.15</version>
</dependency>
</dependencies>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.cloudfoundry.runtime</groupId>
<artifactId>parent</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<artifactId>hello</artifactId>
<packaging>war</packaging>
<name>hello</name>
<dependencies>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-openid</artifactId>
<version>${spring.security.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.8.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.5.8</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</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-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</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-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</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>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>${spring.security.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>${spring.security.oauth.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>${spring.security.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring.security.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.8.3</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.5.8</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.5.8</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.1.1</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</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>
<groupId>org.cloudfoundry.runtime</groupId>
<artifactId>parent</artifactId>
<name>parent</name>
<packaging>pom</packaging>
<version>1.0.0.BUILD-SNAPSHOT</version>
<modules>
<module>auth</module>
<module>api</module>
<module>app</module>
<module>hello</module>
</modules>
<properties>
<spring.version>3.1.0.RELEASE</spring.version>
<spring.security.version>3.1.0.RELEASE</spring.security.version>
<spring.security.oauth.version>1.0.0.BUILD-SNAPSHOT</spring.security.oauth.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-idea-plugin</artifactId>
<version>2.3-atlassian-1</version>
<configuration>
<downloadSources>true</downloadSources>
<downloadJavadocs>true</downloadJavadocs>
<exclude>cargo-installs,target/tomcat5x,target/war</exclude>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<configuration>
<additionalProjectnatures>
<projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
</additionalProjectnatures>
<additionalBuildcommands>
<buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
</additionalBuildcommands>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.1.2</version>
<executions>
<execution>
<id>attach-sources</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<version>6.1.25</version>
</plugin>
</plugins>
</pluginManagement>
<extensions>
<extension>
<groupId>org.springframework.build.aws</groupId>
<artifactId>org.springframework.build.aws.maven</artifactId>
<version>3.0.0.RELEASE</version>
</extension>
</extensions>
</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>
<!-- necessary for Spring Security 3.1.0.CI-SNAPSHOT dependency -->
<id>repository.springframework.maven.snapshot</id>
<name>Spring Framework Maven Release Repository</name>
<url>http://maven.springframework.org/snapshot</url>
</repository>
<repository>
<id>oauth.googlecode.net</id>
<url>http://oauth.googlecode.com/svn/code/maven/</url>
</repository>
<!-- <repository>
<id>java.net</id>
<url>http://download.java.net/maven/2</url>
</repository>-->
</repositories>
<pluginRepositories>
<pluginRepository>
<id>atlassian</id>
<url>https://maven.atlassian.com/repository/public</url>
</pluginRepository>
</pluginRepositories>
<distributionManagement>
<repository>
<id>spring-milestone</id>
<name>Spring Milestone Repository</name>
<url>s3://maven.springframework.org/milestone</url>
</repository>
<snapshotRepository>
<id>spring-snapshot</id>
<name>Spring Snapshot Repository</name>
<url>s3://maven.springframework.org/snapshot</url>
</snapshotRepository>
</distributionManagement>
</project>
/*
* 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.cloudfoundry.identity.app.web;
import static org.junit.Assert.assertEquals;
import java.io.StringReader;
import java.io.StringWriter;
import org.codehaus.jackson.annotate.JsonValue;
import org.codehaus.jackson.map.ObjectMapper;
import org.junit.Test;
import org.springframework.security.openid.OpenIDAuthenticationStatus;
/**
* @author Dave Syer
*
*/
public class SerializationTests {
@Test
public void testOpenIDStatus() throws Exception {
OpenIDAuthenticationStatus status = OpenIDAuthenticationStatus.SUCCESS;
ObjectMapper mapper = new ObjectMapper();
StringWriter string = new StringWriter();
mapper.writeValue(string, status);
System.err.println(string);
OpenIDAuthenticationStatus value = mapper.readValue(new StringReader(string.toString()), OpenIDAuthenticationStatus.class);
assertEquals(status.toString(), value.toString());
// TODO: these are not equal because of the weird implementation of OpenIDAuthenticationStatus
assertEquals(status, value);
}
@Test
public void testCustomStatus() throws Exception {
Status status = Status.SUCCESS;
ObjectMapper mapper = new ObjectMapper();
mapper.getSerializationConfig().addMixInAnnotations(Status.class, StatusHelper.class);
mapper.getDeserializationConfig().addMixInAnnotations(Status.class, StatusHelper.class);
StringWriter string = new StringWriter();
mapper.writeValue(string, status);
System.err.println(string);
Status value = mapper.readValue(new StringReader(string.toString()), Status.class);
assertEquals(status.toString(), value.toString());
// TODO: these are not equal because of the weird implementation of Status
// assertEquals(status, value);
}
public static abstract class StatusHelper {
public StatusHelper(String value) {
}
@Override
@JsonValue
public String toString() {
return super.toString();
}
}
public static class Status {
public static Status SUCCESS = new Status("success");
public static Status FAILED = new Status("failed");
private final String name;
private Status(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}
}
server.port=9005
server.trace=true
server.database.0=file:target/hsqldb-data/samples
server.dbname.0=samples
/*
* 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.cloudfoundry.identity.uaa.web;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.openid4java.server.InMemoryServerAssociationStore;
import org.openid4java.server.ServerManager;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
/**
* @author Dave Syer
*
*/
public class ServerManagerInitializerInterceptor extends HandlerInterceptorAdapter {
private final OpenIdProviderController controller;
private ServerManager manager;
private String endpointUrl;
public void setEndpointUrl(String endpointUrl) {
this.endpointUrl = endpointUrl;
}
public ServerManagerInitializerInterceptor(OpenIdProviderController controller) {
this.controller = controller;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
initialize(request);
return true;
}
private void initialize(HttpServletRequest request) {
request.getSession(true);
if (manager == null) {
manager = new ServerManager();
manager.setSharedAssociations(new InMemoryServerAssociationStore());
manager.setPrivateAssociations(new InMemoryServerAssociationStore());
if(endpointUrl != null) {
manager.setOPEndpointUrl(endpointUrl);
}
else {
manager.setOPEndpointUrl(request.getScheme() + "://" + request.getServerName() + ":"
+ request.getServerPort() + request.getContextPath() + "/openid/provider");
}
controller.setServerManager(manager);
}
}
}
package org.cloudfoundry.identity.app.web;
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.List;
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.TestWatchman;
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.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 extends TestWatchman {
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;
}
@Override
public Statement apply(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 online = false;
try {
client.getForEntity(new UriTemplate(getUrl("/app/openid")).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 {
if (online) {
serverOffline.put(port, false);
if (!assumeOnline) {
Assume.assumeTrue(serverOffline.get(port));
}
}
else {
serverOnline.put(port, false);
}
}
return super.apply(base, method, target);
}
public String getBaseUrl() {
return "http://" + hostName + ":" + port;
}
public String getUrl(String path) {
try {
if (path.startsWith("http:")) {
return path; // URLDecoder.decode(path, "UTF-8");
}
if (!path.startsWith("/")) {
path = "/" + path;
}
return URLDecoder.decode("http://" + hostName + ":" + port + path, "UTF-8");
}
catch (UnsupportedEncodingException e) {
throw new IllegalStateException("Cannot decode path", e);
}
}
public URI getUri(String path) {
try {
return new URI(getUrl(path));
}
catch (URISyntaxException e) {
throw new IllegalStateException("Cannot decode path", e);
}
}
public ResponseEntity<String> getForString(String path, final HttpHeaders headers) {
HttpEntity<Void> request = new HttpEntity<Void>((Void) null, headers);
URI location = getUri(path);
logger.debug("Request location: " + location);
ResponseEntity<String> result = client.exchange(location, HttpMethod.GET, request, String.class);
List<String> cookies = result.getHeaders().get("Set-Cookie");
if (cookies != null && !cookies.isEmpty()) {
try {
headers.set("Cookie", cookies.get(0));
} catch (Exception e) {
logger.error("Could not set cookie on input headers");
}
}
logger.debug("Result status: " + result.getStatusCode());
logger.debug("Result headers: " + result.getHeaders());
return result;
}
public ResponseEntity<Void> getForResponse(String path, final HttpHeaders headers) {
HttpEntity<Void> request = new HttpEntity<Void>((Void) null, headers);
URI location = getUri(path);
logger.debug("Request location: " + location);
logger.debug("Request headers: " + headers);
ResponseEntity<Void> result = client.exchange(location, HttpMethod.GET, request, null);
List<String> cookies = result.getHeaders().get("Set-Cookie");
if (cookies != null && !cookies.isEmpty()) {
try {
headers.set("Cookie", cookies.get(0));
} catch (Exception e) {
logger.error("Could not set cookie on input headers");
}
}
logger.debug("Result status: " + result.getStatusCode());
logger.debug("Result headers: " + result.getHeaders());
return result;
}
public ResponseEntity<Void> postForRedirect(String path, HttpHeaders headers, MultiValueMap<String, String> params) {
HttpHeaders actualHeaders = new HttpHeaders();
actualHeaders.putAll(headers);
actualHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
URI location = getUri(path);
logger.debug("Request location: " + location);
logger.debug("Request headers: " + actualHeaders);
ResponseEntity<Void> exchange = client.exchange(location, HttpMethod.POST,
new HttpEntity<MultiValueMap<String, String>>(params, actualHeaders), null);
logger.debug("Result status: " + exchange.getStatusCode());
logger.debug("Result headers: " + exchange.getHeaders());
if (exchange.getStatusCode() != HttpStatus.FOUND) {
throw new IllegalStateException("Invalid response from server");
}
location = getUri(exchange.getHeaders().getLocation().toString());
List<String> cookies = exchange.getHeaders().get("Set-Cookie");
if (cookies != null && !cookies.isEmpty()) {
actualHeaders.set("Cookie", cookies.get(0));
}
actualHeaders.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
logger.debug("Request location: " + location);
logger.debug("Request headers: " + actualHeaders);
ResponseEntity<Void> result = client.exchange(location, HttpMethod.GET, new HttpEntity<Void>(null,
actualHeaders), null);
logger.debug("Result status: " + result.getStatusCode());
logger.debug("Result headers: " + result.getHeaders());
return result;
}
public ResponseEntity<String> postForPage(String path, HttpHeaders headers, MultiValueMap<String, String> params) {
HttpHeaders actualHeaders = new HttpHeaders();
actualHeaders.putAll(headers);
actualHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
URI location = getUri(path);
logger.debug("Request location: " + location);
logger.debug("Request headers: " + actualHeaders);
ResponseEntity<Void> exchange = client.exchange(location, HttpMethod.POST,
new HttpEntity<MultiValueMap<String, String>>(params, actualHeaders), null);
logger.debug("Result status: " + exchange.getStatusCode());
logger.debug("Result headers: " + exchange.getHeaders());
if (exchange.getStatusCode() != HttpStatus.FOUND) {
throw new IllegalStateException("Invalid response from server");
}
location = getUri(exchange.getHeaders().getLocation().toString());
List<String> cookies = exchange.getHeaders().get("Set-Cookie");
if (cookies != null && !cookies.isEmpty()) {
actualHeaders.set("Cookie", cookies.get(0));
try {
headers.set("Cookie", cookies.get(0));
} catch (Exception e) {
logger.error("Could noit set cookie on input headers");
}
}
actualHeaders.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
logger.debug("Request location: " + location);
logger.debug("Request headers: " + actualHeaders);
ResponseEntity<String> response = client.exchange(location, HttpMethod.GET, new HttpEntity<Void>(null,
actualHeaders), String.class);
logger.debug("Result status: " + response.getStatusCode());
logger.debug("Result headers: " + response.getHeaders());
return response;
}
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(getUri(path), HttpMethod.GET, requestCallback,
new ResponseExtractor<ResponseEntity<String>>() {
public ResponseEntity<String> extractData(ClientHttpResponse response) throws IOException {
return new ResponseEntity<String>(response.getStatusCode());
}
}).getStatusCode();
}
public HttpStatus getStatusCode(String path) {
return getStatusCode(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);
}
}
}
}
package org.cloudfoundry.identity.uaa.web;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
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.junit.Assume;
import org.junit.internal.AssumptionViolatedException;
import org.junit.rules.TestWatchman;
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.HttpComponentsClientHttpRequestFactory;
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 extends TestWatchman {
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;
}
@Override
public Statement apply(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 online = false;
try {
client.getForEntity(new UriTemplate(getUrl("/auth/login")).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 {
if (online) {
serverOffline.put(port, false);
if (!assumeOnline) {
Assume.assumeTrue(serverOffline.get(port));
}
}
else {
serverOnline.put(port, false);
}
}
return super.apply(base, method, target);
}
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) {
return postForString(path, formData, new HttpHeaders());
}
@SuppressWarnings("rawtypes")
public ResponseEntity<Map> postForMap(String path, MultiValueMap<String, String> formData) {
return postForMap(path, formData, new HttpHeaders());
}
@SuppressWarnings("rawtypes")
public ResponseEntity<Map> postForMap(String path, MultiValueMap<String, String> formData, HttpHeaders headers) {
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<String> postForString(String path, MultiValueMap<String, String> formData, HttpHeaders headers) {
if (headers.getContentType() == null) {
headers.setContentType(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) {
return client.exchange(getUrl(path), HttpMethod.GET, new HttpEntity<Void>((Void) null), String.class);
}
public ResponseEntity<String> getForString(String path, final HttpHeaders headers) {
HttpEntity<Void> request = new HttpEntity<Void>((Void) null, headers);
return client.exchange(getUrl(path), HttpMethod.GET, request, String.class);
}
public ResponseEntity<Void> getForResponse(String path, final HttpHeaders headers) {
HttpEntity<Void> request = new HttpEntity<Void>((Void) null, headers);
return client.exchange(getUrl(path), HttpMethod.GET, request, null);
}
public ResponseEntity<Void> postForRedirect(String path, HttpHeaders headers, MultiValueMap<String, String> params) {
HttpHeaders actualHeaders = new HttpHeaders();
actualHeaders.putAll(headers);
actualHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
ResponseEntity<Void> exchange = client.exchange(getUrl(path), HttpMethod.POST,
new HttpEntity<MultiValueMap<String, String>>(params, actualHeaders), null);
if (exchange.getStatusCode() != HttpStatus.FOUND) {
throw new IllegalStateException("Invalid response from server");
}
String location = exchange.getHeaders().getLocation().toString();
List<String> cookies = exchange.getHeaders().get("Set-Cookie");
if (cookies != null && !cookies.isEmpty()) {
actualHeaders.add("Cookie", cookies.get(0));
}
actualHeaders.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
logger.debug("Request location: " + location);
logger.debug("Request headers: " + actualHeaders);
ResponseEntity<Void> result = client.exchange(location, HttpMethod.GET, new HttpEntity<Void>(null,
actualHeaders), null);
logger.debug("Result status: " + result.getStatusCode());
logger.debug("Result headers: " + result.getHeaders());
return result;
}
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<String>>() {
public ResponseEntity<String> extractData(ClientHttpResponse response) throws IOException {
return new ResponseEntity<String>(response.getStatusCode());
}
}).getStatusCode();
}
public HttpStatus getStatusCode(String path) {
return getStatusCode(getUrl(path), null);
}
public RestTemplate getRestTemplate() {
RestTemplate client = new RestTemplate();
client.setRequestFactory(new HttpComponentsClientHttpRequestFactory() {
@Override
public HttpClient getHttpClient() {
HttpClient client = super.getHttpClient();
client.getParams().setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, false);
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));
}
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);
}
}
}
}
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-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/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 pattern="/denied" security="none" xmlns="http://www.springframework.org/schema/security" />
<!-- TODO: make an access denied view that tells me something useful -->
<http access-denied-page="/denied" entry-point-ref="authenticationEntryPoint" access-decision-manager-ref="accessDecisionManager"
xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/photos/**" access="SCOPE_READ_PHOTOS" />
<intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
<custom-filter ref="oauth2ServiceFilter" before="EXCEPTION_TRANSLATION_FILTER" />
<anonymous />
</http>
<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.AuthenticatedVoter" />
</list>
</constructor-arg>
</bean>
<authentication-manager xmlns="http://www.springframework.org/schema/security" />
<bean id="authenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint"
xmlns="http://www.springframework.org/schema/beans">
<property name="loginFormUrl" value="${auth.url}" />
</bean>
<bean id="propertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
xmlns="http://www.springframework.org/schema/beans">
<property name="location">
<value>#{T(java.lang.System).getenv('VCAP_APPLICATION')==null ? 'classpath:/application.properties' :
'classpath:/application-cloud.properties'}
</value>
</property>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" xmlns="http://www.springframework.org/schema/beans">
<property name="driverClassName" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.user}" />
<property name="password" value="${jdbc.password}" />
<property name="testWhileIdle" value="${jdbc.testWhileIdle}" />
<property name="validationQuery" value="${jdbc.validationQuery}" />
</bean>
<bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.RandomValueTokenServices">
<property name="tokenStore">
<bean class="org.springframework.security.oauth2.provider.token.JdbcTokenStore">
<constructor-arg ref="dataSource" />
</bean>
</property>
<property name="supportRefreshToken" value="true" />
</bean>
<oauth:resource-server id="oauth2ServiceFilter" resource-id="api" token-services-ref="tokenServices"/>
<mvc:annotation-driven />
<mvc:default-servlet-handler />
<bean id="viewResolver" class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
<entry key="xml" value="application/xml" />
</map>
</property>
<property name="defaultViews">
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
</property>
</bean>
<bean id="photoController" class="org.cloudfoundry.identity.api.web.mvc.PhotoController">
<property name="photoService" ref="photoServices" />
</bean>
<bean id="photoServices" class="org.cloudfoundry.identity.api.service.PhotoServiceImpl">
<property name="photos">
<list>
<bean class="org.cloudfoundry.identity.api.PhotoInfo">
<property name="id" value="1" />
<property name="name" value="photo1.jpg" />
<property name="userId" value="marissa" />
<property name="resourceURL" value="/org/cloudfoundry/identity/api/web/impl/resources/photo1.jpg" />
</bean>
<bean class="org.cloudfoundry.identity.api.PhotoInfo">
<property name="id" value="2" />
<property name="name" value="photo2.jpg" />
<property name="userId" value="olds@vmware.com" />
<property name="resourceURL" value="/org/cloudfoundry/identity/api/web/impl/resources/photo2.jpg" />
</bean>
<bean class="org.cloudfoundry.identity.api.PhotoInfo">
<property name="id" value="3" />
<property name="name" value="photo3.jpg" />
<property name="userId" value="marissa" />
<property name="resourceURL" value="/org/cloudfoundry/identity/api/web/impl/resources/photo3.jpg" />
</bean>
<bean class="org.cloudfoundry.identity.api.PhotoInfo">
<property name="id" value="4" />
<property name="name" value="photo4.jpg" />
<property name="userId" value="olds@vmware.com" />
<property name="resourceURL" value="/org/cloudfoundry/identity/api/web/impl/resources/photo4.jpg" />
</bean>
<bean class="org.cloudfoundry.identity.api.PhotoInfo">
<property name="id" value="5" />
<property name="name" value="photo5.jpg" />
<property name="userId" value="marissa" />
<property name="resourceURL" value="/org/cloudfoundry/identity/api/web/impl/resources/photo5.jpg" />
</bean>
<bean class="org.cloudfoundry.identity.api.PhotoInfo">
<property name="id" value="6" />
<property name="name" value="photo6.jpg" />
<property name="userId" value="paul" />
<property name="resourceURL" value="/org/cloudfoundry/identity/api/web/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:oauth="http://www.springframework.org/schema/security/oauth2"
xmlns:context="http://www.springframework.org/schema/context" xmlns:sec="http://www.springframework.org/schema/security"
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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<sec:http pattern="/loggedout.jsp" security="none" />
<sec:http pattern="/login_error.jsp" security="none" />
<sec:http pattern="/resources/**" security="none" />
<sec:http pattern="/favicon.ico" security="none" />
<http xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/**" access="ROLE_USER" />
<logout logout-success-url="/loggedout.jsp" />
<openid-login login-page="#{loginController.loginUrl}" login-processing-url="/login" user-service-ref="registeringUserService"
authentication-failure-url="/login_error.jsp">
<attribute-exchange identifier-match=".*">
<openid-attribute name="email" type="http://schema.openid.net/contact/email" required="true" />
<openid-attribute name="fullname" type="http://schema.openid.net/namePerson" required="true" />
</attribute-exchange>
</openid-login>
<custom-filter ref="oauth2ClientFilter" after="EXCEPTION_TRANSLATION_FILTER" />
</http>
<sec:authentication-manager alias="authenticationManager" />
<!--apply the oauth client context -->
<oauth:client id="oauth2ClientFilter" />
<bean id="registeringUserService" class="org.cloudfoundry.identity.openid.user.CustomUserDetailsService" />
<mvc:resources location="/resources/" mapping="/resources/**" />
<mvc:annotation-driven />
<mvc:default-servlet-handler />
<bean id="viewResolver" 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>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/" />
<property name="suffix" value=".jsp" />
</bean>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" xmlns="http://www.springframework.org/schema/beans">
<property name="location">
<value>#{T(java.lang.System).getenv('VCAP_APPLICATION')==null ? 'classpath:/application.properties' :
'classpath:/application-cloud.properties'}
</value>
</property>
</bean>
<bean id="loginController" class="org.cloudfoundry.identity.app.web.LoginController">
<property name="openidProviderUrl" value="${openidProviderUrl}" />
</bean>
<bean id="photoController" class="org.cloudfoundry.identity.app.web.PhotoController">
<property name="restTemplate">
<bean class="org.springframework.security.oauth2.client.OAuth2RestTemplate">
<constructor-arg ref="api" />
</bean>
</property>
<property name="photoListUrl" value="${photoListUrl}" />
<property name="photoUrlPattern" value="${photoUrlPattern}" />
<property name="photoUrlPassthruPattern" value="${photoUrlPassthruPattern}" />
</bean>
<!--define an oauth 2 resource for api access -->
<oauth:resource id="api" type="authorization_code" client-id="app" client-secret="appclientsecret"
access-token-uri="${accessTokenUri}" user-authorization-uri="${userAuthorizationUri}" scope="read_photos" />
</beans>
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
xmlns:sec="http://www.springframework.org/schema/security" xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<sec:http pattern="/resources/**" security="none" />
<sec:http pattern="/favicon.ico" security="none" />
<sec:http pattern="/openid" security="none" />
<sec:http pattern="/openid/users/*" security="none" />
<http pattern="/oauth/token" create-session="never" authentication-manager-ref="clientAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />
<anonymous enabled="false" />
<http-basic />
</http>
<http access-denied-page="/" xmlns="http://www.springframework.org/schema/security">
<!-- machine API access to the authorization process itself is allowed -->
<intercept-url pattern="/openid/provider" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/openid/**" access="ROLE_USER" />
<intercept-url pattern="/login**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/oauth/**" access="ROLE_USER" />
<intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
<form-login authentication-failure-url="/login" login-page="/login" login-processing-url="/login.do"
username-parameter="username" password-parameter="password" />
<anonymous />
<logout logout-success-url="/" logout-url="/logout.do" />
</http>
<authentication-manager erase-credentials="false" alias="authenticationManager"
xmlns="http://www.springframework.org/schema/security">
<!-- provider for tests -->
<authentication-provider>
<user-service>
<user name="marissa" authorities="ROLE_USER" password="koala" />
</user-service>
</authentication-provider>
</authentication-manager>
<bean id="clientCredentialsTokenEndpointFilter" class="org.springframework.security.oauth2.provider.filter.ClientCredentialsTokenEndpointFilter">
<property name="authenticationManager" ref="clientAuthenticationManager" />
</bean>
<authentication-manager id="clientAuthenticationManager" xmlns="http://www.springframework.org/schema/security">
<authentication-provider user-service-ref="clientDetailsUserService" />
</authentication-manager>
<bean id="clientDetailsUserService" class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="clientDetails" />
</bean>
<context:property-placeholder location="classpath:/application.properties" />
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.user}" />
<property name="password" value="${jdbc.password}" />
<property name="testWhileIdle" value="${jdbc.testWhileIdle}" />
<property name="validationQuery" value="${jdbc.validationQuery}" />
</bean>
<bean class="org.springframework.jdbc.datasource.init.DataSourceInitializer">
<property name="databasePopulator">
<bean class="org.springframework.jdbc.datasource.init.ResourceDatabasePopulator">
<property name="scripts"
value="classpath:/create-schema#{T(java.lang.System).getenv('VCAP_APPLICATION')==null ? '' : '-mysql'}.sql" />
<property name="ignoreFailedDrops" value="true" />
</bean>
</property>
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.RandomValueTokenServices">
<property name="tokenStore" ref="tokenStore" />
<property name="supportRefreshToken" value="true" />
</bean>
<bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.JdbcTokenStore">
<constructor-arg ref="dataSource" />
</bean>
<oauth:authorization-server client-details-service-ref="clientDetails" token-services-ref="tokenServices">
<oauth:authorization-code />
<oauth:implicit />
<oauth:refresh-token />
<oauth:client-credentials />
<oauth:password />
</oauth:authorization-server>
<oauth:client-details-service id="clientDetails">
<oauth:client client-id="app" authorized-grant-types="password,authorization_code,refresh_token,implicit"
scope="read_photos" authorities="ROLE_GUEST" secret="appclientsecret" />
</oauth:client-details-service>
<mvc:resources location="/resources/" mapping="/resources/**" />
<mvc:annotation-driven />
<mvc:default-servlet-handler />
<mvc:interceptors>
<bean class="org.cloudfoundry.identity.uaa.web.ServerManagerInitializerInterceptor">
<constructor-arg ref="openidController" />
<property name="endpointUrl" value="${endpointUrl}"></property>
</bean>
</mvc:interceptors>
<bean id="viewResolver" class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="mediaTypes">
<map>
<entry key="html" value="text/html" />
<entry key="json" value="application/json" />
</map>
</property>
<property name="viewResolvers">
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
</property>
<property name="defaultViews">
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
</property>
</bean>
<!--Basic application beans. -->
<bean id="accessConfirmationController" class="org.cloudfoundry.identity.uaa.web.AccessController">
<property name="clientDetailsService" ref="clientDetails" />
</bean>
<bean id="openidController" class="org.cloudfoundry.identity.uaa.web.OpenIdProviderController" />
</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:oauth="http://www.springframework.org/schema/security/oauth2"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:sec="http://www.springframework.org/schema/security"
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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<sec:http pattern="/openid" security="none" />
<sec:http pattern="/loggedout.jsp" security="none" />
<sec:http pattern="/login_error.jsp" security="none" />
<sec:http pattern="/resources/**" security="none" />
<sec:http pattern="/favicon.ico" security="none" />
<http xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/**" access="ROLE_USER" />
<logout logout-success-url="/loggedout.jsp"/>
<openid-login login-page="#{loginController.loginUrl}" login-processing-url="/login"
user-service-ref="registeringUserService" authentication-failure-url="/login_error.jsp">
<attribute-exchange identifier-match=".*">
<openid-attribute name="email"
type="http://schema.openid.net/contact/email" required="true" />
<openid-attribute name="fullname"
type="http://schema.openid.net/namePerson" required="true" />
</attribute-exchange>
</openid-login>
</http>
<sec:authentication-manager alias="authenticationManager" />
<bean id="registeringUserService"
class="org.cloudfoundry.identity.openid.user.CustomUserDetailsService" />
<mvc:resources location="/resources/" mapping="/resources/**" />
<mvc:annotation-driven />
<mvc:default-servlet-handler />
<bean id="viewResolver" 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>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/" />
<property name="suffix" value=".jsp" />
</bean>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" xmlns="http://www.springframework.org/schema/beans">
<property name="location">
<value>#{T(java.lang.System).getenv('VCAP_APPLICATION')==null ? 'classpath:/application.properties' :
'classpath:/application-cloud.properties'}</value>
</property>
</bean>
<bean id="loginController" class="org.cloudfoundry.identity.app.web.LoginController">
<property name="openidProviderUrl" value="${openidProviderUrl}" />
</bean>
</beans>
/* CSS Document */
body {
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' );
color: white;
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: blue;
font-weight: bold;
font-size: 1em
}
#footer a:hover {
color: red;
font-weight: bold;
font-size: 1em
}
/* 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
}
/* CSS Document */
body {
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' );
color: yellow;
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: blue;
font-weight: bold;
font-size: 1em
}
#footer a:hover {
color: red;
font-weight: bold;
font-size: 1em
}
package org.cloudfoundry.identity.uaa.web;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.net.URI;
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.http.ResponseEntity;
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();
/**
* tests the basic implicit provider
*/
@Test
public void testBasicImplicitProvider() throws Exception {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
URI uri = serverRunning.buildUri("/auth/oauth/authorize").queryParam("response_type", "token")
.queryParam("client_id", "app").queryParam("client_secret", "appclientsecret")
.queryParam("redirect_uri", "http://anywhere").queryParam("scope", "read_photos").build();
ResponseEntity<Void> result = serverRunning.getForResponse(uri.toString(), headers);
assertEquals(HttpStatus.FOUND, result.getStatusCode());
String location = result.getHeaders().getLocation().toString();
String cookie = result.getHeaders().getFirst("Set-Cookie");
assertNotNull("Expected cookie in " + result.getHeaders(), cookie);
headers.set("Cookie", cookie);
ResponseEntity<String> response = serverRunning.getForString(location, headers);
// should be directed to the login screen...
assertTrue(response.getBody().contains("auth/login.do"));
assertTrue(response.getBody().contains("username"));
assertTrue(response.getBody().contains("password"));
location = "auth/login.do";
MultiValueMap<String, String> formData = new LinkedMultiValueMap<String, String>();
formData.add("username", "marissa");
formData.add("password", "koala");
result = serverRunning.postForRedirect(location, headers, formData);
assertNotNull(result.getHeaders().getLocation());
location = result.getHeaders().getLocation().toString();
assertTrue(location.contains("anywhere"));
assertTrue(location.contains("#"));
}
}
package org.cloudfoundry.identity.uaa.web;
import static org.junit.Assert.assertEquals;
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.http.ResponseEntity;
import org.springframework.security.crypto.codec.Base64;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
/**
* @author Ryan Heaton
* @author Dave Syer
*/
public class TestNativeApplicationProfile {
@Rule
public ServerRunning serverRunning = ServerRunning.isRunning();
/**
* tests a happy-day flow of the Resource Owner Password Credentials grant type.
* (formerly native application profile).
*/
@Test
public void testHappyDay() throws Exception {
MultiValueMap<String, String> formData = new LinkedMultiValueMap<String, String>();
formData.add("grant_type", "password");
formData.add("client_id", "app");
formData.add("client_secret", "appclientsecret");
formData.add("username", "marissa");
formData.add("password", "koala");
formData.add("scope", "read_photos");
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Basic " + new String(Base64.encode("app:appclientsecret".getBytes("UTF-8"))));
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
ResponseEntity<String> response = serverRunning.postForString("/auth/oauth/token", formData, headers);
assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals("no-store", response.getHeaders().getFirst("Cache-Control"));
}
}
package org.cloudfoundry.identity.uaa.web;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import java.util.Arrays;
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.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.codec.Base64;
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();
@Test
public void testHappyDay() throws Exception {
MultiValueMap<String, String> formData = new LinkedMultiValueMap<String, String>();
formData.add("grant_type", "password");
formData.add("client_id", "app");
formData.add("username", "marissa");
formData.add("password", "koala");
formData.add("scope", "read_photos");
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Basic " + new String(Base64.encode("app:appclientsecret".getBytes("UTF-8"))));
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
@SuppressWarnings("rawtypes")
ResponseEntity<Map> response = serverRunning.postForMap("/auth/oauth/token", formData, headers );
assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals("no-store", response.getHeaders().getFirst("Cache-Control"));
@SuppressWarnings("unchecked")
OAuth2AccessToken accessToken =OAuth2AccessToken.valueOf(response.getBody());
// now use the refresh token to get a new access token.
assertNotNull(accessToken.getRefreshToken());
formData = new LinkedMultiValueMap<String, String>();
formData.add("grant_type", "refresh_token");
formData.add("refresh_token", accessToken.getRefreshToken().getValue());
response = serverRunning.postForMap("/auth/oauth/token", formData, headers);
assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals("no-store", response.getHeaders().getFirst("Cache-Control"));
@SuppressWarnings("unchecked")
OAuth2AccessToken newAccessToken = OAuth2AccessToken.valueOf(response.getBody());
assertFalse(newAccessToken.getValue().equals(accessToken.getValue()));
}
}
package org.cloudfoundry.identity.uaa.web;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.net.URI;
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.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
/**
* @author Ryan Heaton
* @author Dave Syer
*/
public class TestWebServerProfile {
@Rule
public ServerRunning serverRunning = ServerRunning.isRunning();
/**
* tests the basic web server profile
*/
@Test
public void testBasicWebServerProfile() throws Exception {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
URI uri = serverRunning.buildUri("/auth/oauth/authorize").queryParam("response_type", "code")
.queryParam("state", "mystateid").queryParam("client_id", "app")
.queryParam("redirect_uri", "http://anywhere").build();
ResponseEntity<Void> result = serverRunning.getForResponse(uri.toString(), headers);
assertEquals(HttpStatus.FOUND, result.getStatusCode());
String location = result.getHeaders().getLocation().toString();
ResponseEntity<String> response = serverRunning.getForString(location, headers);
// should be directed to the login screen...
assertTrue(response.getBody().contains("auth/login.do"));
assertTrue(response.getBody().contains("username"));
assertTrue(response.getBody().contains("password"));
MultiValueMap<String, String> formData = new LinkedMultiValueMap<String, String>();
formData.add("username", "marissa");
formData.add("password", "koala");
// response = serverRunning.postForString("/auth/login.do", formData, headers);
// TODO finish flow, + or use HTML content type
}
}
dn: ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: groups
dn: ou=people,dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: people
dn: uid=marissa,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Marissa
sn: Marissa
uid: marissa
userPassword: koala
dn: uid=paul,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Paul
sn: Paul
uid: paul
userPassword: emu
dn: cn=user,ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: groupOfNames
cn: user
member: uid=marissa,ou=people,dc=springframework,dc=org
member: uid=paul,ou=people,dc=springframework,dc=org
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4">
<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>
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4">
<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>
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4">
<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>
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4">
<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