diff --git a/pom.xml b/pom.xml index cf45099..deef806 100644 --- a/pom.xml +++ b/pom.xml @@ -14,7 +14,7 @@ org.springframework.boot spring-boot-starter-parent - 1.1.5.BUILD-SNAPSHOT + 1.1.5.RELEASE @@ -34,6 +34,7 @@ org.springframework.platform spring-platform-netflix-core + true org.springframework.boot @@ -44,10 +45,27 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.boot + spring-boot-starter-actuator + true + org.cloudfoundry spring-boot-cf-service-broker 2.3.1 + true + + + org.springframework.security.oauth + spring-security-oauth2 + 2.0.3.BUILD-SNAPSHOT + true + + + org.projectlombok + lombok + provided com.netflix.eureka @@ -59,6 +77,11 @@ spring-boot-starter-test test + + org.apache.ant + ant-launcher + 1.9.3 + diff --git a/src/main/java/org/springframework/platform/cloudfoundry/broker/CatalogLeaseManager.java b/src/main/java/org/springframework/platform/cloudfoundry/broker/configuration/CatalogLeaseManager.java similarity index 89% rename from src/main/java/org/springframework/platform/cloudfoundry/broker/CatalogLeaseManager.java rename to src/main/java/org/springframework/platform/cloudfoundry/broker/configuration/CatalogLeaseManager.java index 7cc9056..a99ca41 100644 --- a/src/main/java/org/springframework/platform/cloudfoundry/broker/CatalogLeaseManager.java +++ b/src/main/java/org/springframework/platform/cloudfoundry/broker/configuration/CatalogLeaseManager.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.platform.cloudfoundry.broker; +package org.springframework.platform.cloudfoundry.broker.configuration; import java.util.ArrayList; import java.util.Collection; @@ -25,7 +25,7 @@ import org.cloudfoundry.community.servicebroker.model.Catalog; import org.cloudfoundry.community.servicebroker.model.ServiceDefinition; import org.cloudfoundry.community.servicebroker.service.BeanCatalogService; import org.cloudfoundry.community.servicebroker.service.CatalogService; -import org.springframework.platform.netflix.eureka.advice.LeaseManagerLite; +import org.springframework.platform.cloudfoundry.broker.FreeServiceDefinitionFactory; import com.netflix.appinfo.InstanceInfo; import com.netflix.appinfo.InstanceInfo.ActionType; @@ -35,15 +35,14 @@ import com.netflix.eureka.lease.LeaseManager; * @author Dave Syer * */ -public class CatalogLeaseManager implements LeaseManager, LeaseManagerLite, - CatalogService { +public class CatalogLeaseManager implements LeaseManager, CatalogService { private Map definitions = new HashMap(); private List values = new ArrayList(); public CatalogLeaseManager(InstanceInfo config) { - register(config, false); + register(config, 0, false); } @Override @@ -56,11 +55,6 @@ public class CatalogLeaseManager implements LeaseManager, LeaseMan return new BeanCatalogService(getCatalog()).getServiceDefinition(serviceId); } - @Override - public void register(InstanceInfo info, boolean isReplication) { - register(info, 0, isReplication); - } - @Override public void register(InstanceInfo info, int leaseDuration, boolean isReplication) { if (!definitions.containsKey(info.getAppName())) { @@ -102,7 +96,8 @@ public class CatalogLeaseManager implements LeaseManager, LeaseMan private ServiceDefinition getServiceDefinition(InstanceInfo info) { String name = info.getAppName().toLowerCase(); - ServiceDefinition definition = new FreeServiceDefinitionFactory("eureka-").create(name, "Eureka-brokered service"); + ServiceDefinition definition = new FreeServiceDefinitionFactory("eureka-") + .create(name, "Eureka-brokered service"); Map map = new HashMap(); map.put("info", (Object) info); map.put("uri", info.getHomePageUrl()); diff --git a/src/main/java/org/springframework/platform/cloudfoundry/broker/ServiceBrokerAutoConfiguration.java b/src/main/java/org/springframework/platform/cloudfoundry/broker/configuration/ServiceBrokerAutoConfiguration.java similarity index 86% rename from src/main/java/org/springframework/platform/cloudfoundry/broker/ServiceBrokerAutoConfiguration.java rename to src/main/java/org/springframework/platform/cloudfoundry/broker/configuration/ServiceBrokerAutoConfiguration.java index ab4c629..22dde4d 100644 --- a/src/main/java/org/springframework/platform/cloudfoundry/broker/ServiceBrokerAutoConfiguration.java +++ b/src/main/java/org/springframework/platform/cloudfoundry/broker/configuration/ServiceBrokerAutoConfiguration.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.platform.cloudfoundry.broker; +package org.springframework.platform.cloudfoundry.broker.configuration; import java.lang.reflect.Field; import java.lang.reflect.Modifier; @@ -41,9 +41,15 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; -import org.springframework.platform.netflix.eureka.EurekaRegistryAvailableEvent; -import org.springframework.platform.netflix.eureka.advice.LeaseManagerLite; +import org.springframework.platform.cloudfoundry.broker.FreeServiceDefinitionFactory; +import org.springframework.platform.cloudfoundry.broker.ServiceInstanceBindingRepository; +import org.springframework.platform.cloudfoundry.broker.ServiceInstanceRepository; +import org.springframework.platform.cloudfoundry.broker.simple.SimpleServiceInstanceBindingRepository; +import org.springframework.platform.cloudfoundry.broker.simple.SimpleServiceInstanceBindingService; +import org.springframework.platform.cloudfoundry.broker.simple.SimpleServiceInstanceRepository; +import org.springframework.platform.cloudfoundry.broker.simple.SimpleServiceInstanceService; import org.springframework.platform.netflix.eureka.advice.PiggybackMethodInterceptor; +import org.springframework.platform.netflix.eureka.event.EurekaRegistryAvailableEvent; import org.springframework.stereotype.Component; import org.springframework.util.ReflectionUtils; @@ -69,21 +75,21 @@ import com.netflix.eureka.lease.LeaseManager; * */ @Configuration -@ComponentScan(basePackages = { "demo", "org.cloudfoundry.community.servicebroker" }, excludeFilters = { +@ComponentScan(basePackages = { "org.cloudfoundry.community.servicebroker" }, excludeFilters = { @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = BrokerApiVersionConfig.class), @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = BeanCatalogService.class) }) -@ConditionalOnClass(ServiceInstanceRepository.class) +@ConditionalOnClass({ServiceInstanceRepository.class, BrokerApiVersionConfig.class }) @ConditionalOnWebApplication public class ServiceBrokerAutoConfiguration { - + @Configuration - @ConditionalOnMissingClass(name="com.netflix.eureka.PeerAwareInstanceRegistry") + @ConditionalOnMissingClass(name = "com.netflix.eureka.PeerAwareInstanceRegistry") @ConditionalOnMissingBean(CatalogService.class) protected static class CatalogConfiguration { - + @Autowired private BrokerProperties broker; - + @Bean public BeanCatalogService catalogService() { return new BeanCatalogService(catalog()); @@ -97,10 +103,10 @@ public class ServiceBrokerAutoConfiguration { @Bean @ConfigurationProperties("cloudfoundry.service.definition") public ServiceDefinition serviceDefinition() { - return new FreeServiceDefinitionFactory(broker.getPrefix()).create(broker.getName(), - broker.getDescription()); + return new FreeServiceDefinitionFactory(broker.getPrefix()).create( + broker.getName(), broker.getDescription()); } - + @Component @ConfigurationProperties("cloudfoundry.server.broker") public static class BrokerProperties { @@ -108,21 +114,27 @@ public class ServiceBrokerAutoConfiguration { @Value("${spring.application.name:application}") private String name; private String description; + public String getPrefix() { - return prefix==null ? name + "-" : prefix; + return prefix == null ? name + "-" : prefix; } + public void setPrefix(String prefix) { this.prefix = prefix; } + public String getName() { return name; } + public void setName(String name) { this.name = name; } + public String getDescription() { return description == null ? "Singleton service app" : description; } + public void setDescription(String description) { this.description = description; } @@ -158,7 +170,7 @@ public class ServiceBrokerAutoConfiguration { ProxyFactory factory = new ProxyFactory( PeerAwareInstanceRegistry.getInstance()); factory.addAdvice(new PiggybackMethodInterceptor(leaseManager, - LeaseManager.class, LeaseManagerLite.class)); + LeaseManager.class)); factory.setProxyTargetClass(true); Field field = ReflectionUtils.findField(PeerAwareInstanceRegistry.class, "instance"); diff --git a/src/main/java/org/springframework/platform/cloudfoundry/broker/SimpleServiceInstanceBindingRepository.java b/src/main/java/org/springframework/platform/cloudfoundry/broker/simple/SimpleServiceInstanceBindingRepository.java similarity index 89% rename from src/main/java/org/springframework/platform/cloudfoundry/broker/SimpleServiceInstanceBindingRepository.java rename to src/main/java/org/springframework/platform/cloudfoundry/broker/simple/SimpleServiceInstanceBindingRepository.java index 7289db4..f1da5e8 100644 --- a/src/main/java/org/springframework/platform/cloudfoundry/broker/SimpleServiceInstanceBindingRepository.java +++ b/src/main/java/org/springframework/platform/cloudfoundry/broker/simple/SimpleServiceInstanceBindingRepository.java @@ -13,9 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.platform.cloudfoundry.broker; +package org.springframework.platform.cloudfoundry.broker.simple; import org.cloudfoundry.community.servicebroker.model.ServiceInstanceBinding; +import org.springframework.platform.cloudfoundry.broker.ServiceInstanceBindingRepository; /** * @author Dave Syer diff --git a/src/main/java/org/springframework/platform/cloudfoundry/broker/SimpleServiceInstanceBindingService.java b/src/main/java/org/springframework/platform/cloudfoundry/broker/simple/SimpleServiceInstanceBindingService.java similarity index 96% rename from src/main/java/org/springframework/platform/cloudfoundry/broker/SimpleServiceInstanceBindingService.java rename to src/main/java/org/springframework/platform/cloudfoundry/broker/simple/SimpleServiceInstanceBindingService.java index eca6246..8e1fd0e 100644 --- a/src/main/java/org/springframework/platform/cloudfoundry/broker/SimpleServiceInstanceBindingService.java +++ b/src/main/java/org/springframework/platform/cloudfoundry/broker/simple/SimpleServiceInstanceBindingService.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.platform.cloudfoundry.broker; +package org.springframework.platform.cloudfoundry.broker.simple; import java.util.HashMap; import java.util.Map; @@ -27,6 +27,7 @@ import org.cloudfoundry.community.servicebroker.service.CatalogService; import org.cloudfoundry.community.servicebroker.service.ServiceInstanceBindingService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.platform.cloudfoundry.broker.ServiceInstanceBindingRepository; import org.springframework.stereotype.Service; /** diff --git a/src/main/java/org/springframework/platform/cloudfoundry/broker/SimpleServiceInstanceRepository.java b/src/main/java/org/springframework/platform/cloudfoundry/broker/simple/SimpleServiceInstanceRepository.java similarity index 90% rename from src/main/java/org/springframework/platform/cloudfoundry/broker/SimpleServiceInstanceRepository.java rename to src/main/java/org/springframework/platform/cloudfoundry/broker/simple/SimpleServiceInstanceRepository.java index c90b95f..617439c 100644 --- a/src/main/java/org/springframework/platform/cloudfoundry/broker/SimpleServiceInstanceRepository.java +++ b/src/main/java/org/springframework/platform/cloudfoundry/broker/simple/SimpleServiceInstanceRepository.java @@ -13,12 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.platform.cloudfoundry.broker; +package org.springframework.platform.cloudfoundry.broker.simple; import java.util.ArrayList; import java.util.List; import org.cloudfoundry.community.servicebroker.model.ServiceInstance; +import org.springframework.platform.cloudfoundry.broker.ServiceInstanceRepository; /** * @author Dave Syer diff --git a/src/main/java/org/springframework/platform/cloudfoundry/broker/SimpleServiceInstanceService.java b/src/main/java/org/springframework/platform/cloudfoundry/broker/simple/SimpleServiceInstanceService.java similarity index 94% rename from src/main/java/org/springframework/platform/cloudfoundry/broker/SimpleServiceInstanceService.java rename to src/main/java/org/springframework/platform/cloudfoundry/broker/simple/SimpleServiceInstanceService.java index abae644..8dcf51c 100644 --- a/src/main/java/org/springframework/platform/cloudfoundry/broker/SimpleServiceInstanceService.java +++ b/src/main/java/org/springframework/platform/cloudfoundry/broker/simple/SimpleServiceInstanceService.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.platform.cloudfoundry.broker; +package org.springframework.platform.cloudfoundry.broker.simple; import java.util.List; @@ -23,6 +23,7 @@ import org.cloudfoundry.community.servicebroker.model.ServiceDefinition; import org.cloudfoundry.community.servicebroker.model.ServiceInstance; import org.cloudfoundry.community.servicebroker.service.ServiceInstanceService; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.platform.cloudfoundry.broker.ServiceInstanceRepository; import org.springframework.stereotype.Service; @Service diff --git a/src/main/java/org/springframework/platform/cloudfoundry/sso/CloudfoundrySsoConfiguration.java b/src/main/java/org/springframework/platform/cloudfoundry/sso/CloudfoundrySsoConfiguration.java new file mode 100644 index 0000000..6a9b451 --- /dev/null +++ b/src/main/java/org/springframework/platform/cloudfoundry/sso/CloudfoundrySsoConfiguration.java @@ -0,0 +1,207 @@ +/* + * Copyright 2013-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.platform.cloudfoundry.sso; + +import java.io.IOException; +import java.util.Collections; +import java.util.List; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.actuate.autoconfigure.ManagementServerProperties; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.boot.autoconfigure.security.SecurityProperties; +import org.springframework.boot.context.embedded.FilterRegistrationBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Scope; +import org.springframework.context.annotation.ScopedProxyMode; +import org.springframework.core.Ordered; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; +import org.springframework.security.core.Authentication; +import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext; +import org.springframework.security.oauth2.client.OAuth2RestOperations; +import org.springframework.security.oauth2.client.OAuth2RestTemplate; +import org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter; +import org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter; +import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails; +import org.springframework.security.oauth2.client.token.AccessTokenRequest; +import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails; +import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client; +import org.springframework.security.oauth2.provider.token.RemoteTokenServices; +import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices; +import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; +import org.springframework.security.web.authentication.logout.LogoutHandler; +import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.util.ClassUtils; + +/** + * @author Dave Syer + * + */ +@Configuration +@ConditionalOnExpression("'${cloudfoundry.sso.tokenUri:${vcap.services.sso.credentials.tokenUri:}}'!=''") +@ConditionalOnClass({ EnableOAuth2Client.class, SecurityProperties.class }) +@ConditionalOnWebApplication +@EnableOAuth2Client +@EnableConfigurationProperties(CloudfoundrySsoProperties.class) +public class CloudfoundrySsoConfiguration { + + @Autowired + private CloudfoundrySsoProperties sso; + + @Resource + @Qualifier("accessTokenRequest") + private AccessTokenRequest accessTokenRequest; + + @Bean + public FilterRegistrationBean oauth2ClientFilterRegistration( + OAuth2ClientContextFilter filter) { + FilterRegistrationBean registration = new FilterRegistrationBean(); + registration.setFilter(filter); + registration.setOrder(0); + return registration; + } + + @Bean + public OAuth2ProtectedResourceDetails remote() { + AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails(); + // set up resource details, OAuth2 URLs etc. + details.setClientId(sso.getClientId()); + details.setClientSecret(sso.getClientSecret()); + details.setAccessTokenUri(sso.getTokenUri()); + details.setUserAuthorizationUri(sso.getAuthorizationUri()); + return details; + } + + @Bean + @Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES) + public OAuth2RestOperations restTemplate() { + return new OAuth2RestTemplate(remote(), new DefaultOAuth2ClientContext( + accessTokenRequest)); + } + + @Configuration + protected static class SsoSecurityConfigurer extends WebSecurityConfigurerAdapter + implements Ordered { + + @Autowired + private OAuth2ProtectedResourceDetails remote; + + @Autowired + private CloudfoundrySsoProperties sso; + + @Autowired + private OAuth2RestOperations restTemplate; + + private List configurers = Collections.emptyList(); + + @Override + public int getOrder() { + if (ClassUtils + .isPresent( + "org.springframework.boot.actuate.autoconfigure.ManagementServerProperties", + null)) { + return ManagementServerProperties.ACCESS_OVERRIDE_ORDER; + } + return SecurityProperties.ACCESS_OVERRIDE_ORDER; + } + + /** + * @param configurers the configurers to set + */ + @Autowired(required = false) + public void setConfigurers(List configurers) { + this.configurers = configurers; + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + + http.addFilterAfter(cloudfoundrySsoFilter(), + AbstractPreAuthenticatedProcessingFilter.class); + + for (CloudfoundrySsoConfigurer configurer : configurers) { + // Delegates can add authorizeRequests() here + configurer.configure(http); + } + if (configurers.isEmpty()) { + // Add anyRequest() last as a fall back. Spring Security would replace an + // existing anyRequest() matcher with this one, so to avoid that we only + // add it if the user hasn't configured anything. + ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry requests = http + .antMatcher("/**").authorizeRequests(); + if (!sso.getHome().isSecure()) { + requests.antMatchers(sso.getHome().getPath()).permitAll(); + } + requests.anyRequest().authenticated(); + } + + http.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")) + .addLogoutHandler(logoutHandler()); + http.exceptionHandling().authenticationEntryPoint( + new LoginUrlAuthenticationEntryPoint("/login")); + + } + + protected OAuth2ClientAuthenticationProcessingFilter cloudfoundrySsoFilter() { + OAuth2ClientAuthenticationProcessingFilter filter = new OAuth2ClientAuthenticationProcessingFilter( + "/login"); + filter.setRestTemplate(restTemplate); + filter.setTokenServices(tokenServices()); + return filter; + } + + private ResourceServerTokenServices tokenServices() { + RemoteTokenServices services = new RemoteTokenServices(); + services.setCheckTokenEndpointUrl(sso.getTokenInfoUri()); + services.setClientId(sso.getClientId()); + services.setClientSecret(sso.getClientSecret()); + return services; + } + + private LogoutHandler logoutHandler() { + LogoutHandler handler = new LogoutHandler() { + @Override + public void logout(HttpServletRequest request, + HttpServletResponse response, Authentication authentication) { + restTemplate.getOAuth2ClientContext().setAccessToken(null); + String redirect = request.getRequestURL().toString() + .replace("/logout", sso.getHome().getPath()); + try { + response.sendRedirect(sso.getLogoutUri(redirect)); + } + catch (IOException e) { + throw new IllegalStateException("Cannot logout", e); + } + } + }; + return handler; + } + + } + +} diff --git a/src/main/java/org/springframework/platform/cloudfoundry/sso/CloudfoundrySsoConfigurer.java b/src/main/java/org/springframework/platform/cloudfoundry/sso/CloudfoundrySsoConfigurer.java new file mode 100644 index 0000000..7fca0c1 --- /dev/null +++ b/src/main/java/org/springframework/platform/cloudfoundry/sso/CloudfoundrySsoConfigurer.java @@ -0,0 +1,28 @@ +/* + * Copyright 2013-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.platform.cloudfoundry.sso; + +import org.springframework.security.config.annotation.web.builders.HttpSecurity; + +/** + * @author Dave Syer + * + */ +public interface CloudfoundrySsoConfigurer { + + void configure(HttpSecurity http); + +} diff --git a/src/main/java/org/springframework/platform/cloudfoundry/sso/CloudfoundrySsoConfigurerAdapter.java b/src/main/java/org/springframework/platform/cloudfoundry/sso/CloudfoundrySsoConfigurerAdapter.java new file mode 100644 index 0000000..ee19e75 --- /dev/null +++ b/src/main/java/org/springframework/platform/cloudfoundry/sso/CloudfoundrySsoConfigurerAdapter.java @@ -0,0 +1,30 @@ +/* + * Copyright 2013-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.platform.cloudfoundry.sso; + +import org.springframework.security.config.annotation.web.builders.HttpSecurity; + +/** + * @author Dave Syer + * + */ +public class CloudfoundrySsoConfigurerAdapter implements CloudfoundrySsoConfigurer { + + @Override + public void configure(HttpSecurity http) { + } + +} diff --git a/src/main/java/org/springframework/platform/cloudfoundry/sso/CloudfoundrySsoProperties.java b/src/main/java/org/springframework/platform/cloudfoundry/sso/CloudfoundrySsoProperties.java new file mode 100644 index 0000000..4477226 --- /dev/null +++ b/src/main/java/org/springframework/platform/cloudfoundry/sso/CloudfoundrySsoProperties.java @@ -0,0 +1,87 @@ +/* + * Copyright 2013-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.platform.cloudfoundry.sso; + +import lombok.Data; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.util.StringUtils; +import org.springframework.validation.Errors; +import org.springframework.validation.Validator; + +/** + * @author Dave Syer + * + */ +@ConfigurationProperties("cloudfoundry.sso") +@Data +public class CloudfoundrySsoProperties implements Validator { + + @Value("${vcap.services.sso.credentials.tokenUri:}") + private String tokenUri; + + @Value("${vcap.services.sso.credentials.authorizationUri:}") + private String authorizationUri; + + @Value("${vcap.services.sso.credentials.clientId:}") + private String clientId; + + @Value("${vcap.services.sso.credentials.clientSecret:}") + private String clientSecret; + + private Home home = new Home(); + + @Data + public static class Home { + private String path = "/"; + private boolean secure = true; + } + + public String getTokenInfoUri() { + return tokenUri.replace("/oauth/token", "/check_token"); + } + + public String getUserInfoUri() { + return tokenUri.replace("/oauth/token", "/user_info"); + } + + public String getLogoutUri(String redirectUrl) { + return tokenUri.replace("/oauth/token", "/logout.do?redirect="+redirectUrl); + } + + @Override + public boolean supports(Class clazz) { + return CloudfoundrySsoProperties.class.isAssignableFrom(clazz); + } + + @Override + public void validate(Object target, Errors errors) { + CloudfoundrySsoProperties sso = (CloudfoundrySsoProperties) target; + if (StringUtils.hasText(sso.getTokenUri())) { + if (!StringUtils.hasText(sso.getAuthorizationUri())) { + errors.rejectValue("authorizeUri", "missing.authorizeUri", "Missing authorizeUri"); + } + if (!StringUtils.hasText(sso.getClientId())) { + errors.rejectValue("clientId", "missing.clientId", "Missing clientId"); + } + if (!StringUtils.hasText(sso.getClientSecret())) { + errors.rejectValue("clientSecret", "missing.clientSecret", "Missing clientSecret"); + } + } + } + +} diff --git a/src/main/java/org/springframework/platform/cloudfoundry/sso/EnableCloudfoundrySso.java b/src/main/java/org/springframework/platform/cloudfoundry/sso/EnableCloudfoundrySso.java new file mode 100644 index 0000000..aaed424 --- /dev/null +++ b/src/main/java/org/springframework/platform/cloudfoundry/sso/EnableCloudfoundrySso.java @@ -0,0 +1,36 @@ +/* + * Copyright 2013-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.platform.cloudfoundry.sso; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.context.annotation.Import; + +/** + * @author Dave Syer + * + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Import(CloudfoundrySsoConfiguration.class) +public @interface EnableCloudfoundrySso { + +} diff --git a/src/main/resources/META-INF/spring.factories b/src/main/resources/META-INF/spring.factories index a8cd9d1..5ba9287 100644 --- a/src/main/resources/META-INF/spring.factories +++ b/src/main/resources/META-INF/spring.factories @@ -1,2 +1,2 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ -org.springframework.platform.cloudfoundry.broker.ServiceBrokerAutoConfiguration \ No newline at end of file +org.springframework.platform.cloudfoundry.broker.configuration.ServiceBrokerAutoConfiguration \ No newline at end of file diff --git a/src/test/java/org/springframework/platform/cloudfoundry/broker/sample/Application.java b/src/test/java/org/springframework/platform/cloudfoundry/broker/sample/Application.java index c4077ad..4a8eb7d 100644 --- a/src/test/java/org/springframework/platform/cloudfoundry/broker/sample/Application.java +++ b/src/test/java/org/springframework/platform/cloudfoundry/broker/sample/Application.java @@ -18,9 +18,11 @@ package org.springframework.platform.cloudfoundry.broker.sample; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.context.annotation.Configuration; +import org.springframework.platform.cloudfoundry.sso.EnableCloudfoundrySso; @Configuration @EnableAutoConfiguration +@EnableCloudfoundrySso public class Application { public static void main(String[] args) { diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml index ab78716..843114b 100644 --- a/src/test/resources/application.yml +++ b/src/test/resources/application.yml @@ -1,15 +1,27 @@ debug: true +server: + port: 8787 spring: application: name: eureka management: context-path: /admin +cloudfoundry: + sso: + tokenUri: http://localhost:8080/uaa/oauth/token + authorizationUri: http://localhost:8080/uaa/oauth/authorize + clientId: app + clientSecret: appclientsecret +logging: + level: + com.netflix.discovery: 'OFF' + org.springframework.security: DEBUG eureka: server: waitTimeInMsWhenSyncEmpty: 1000 client: serviceUrl: - defaultZone: http://localhost:8080/v2/ - default.defaultZone: http://localhost:8080/v2/ + defaultZone: http://localhost:8787/v2/ + default.defaultZone: http://localhost:8787/v2/ registerWithEureka: false fetchRegistry: false \ No newline at end of file