瀏覽代碼

Add hellowebfluxfn

Fixes gh-4338
Rob Winch 8 年之前
父節點
當前提交
f01989ff49

+ 16 - 0
samples/javaconfig/hellowebfluxfn/spring-security-samples-javaconfig-hellowebfluxfn.gradle

@@ -0,0 +1,16 @@
+apply plugin: 'io.spring.convention.spring-sample'
+
+dependencies {
+	compile project(':spring-security-core')
+	compile project(':spring-security-config')
+	compile project(':spring-security-webflux')
+	compile 'com.fasterxml.jackson.core:jackson-databind'
+	compile 'io.netty:netty-buffer'
+	compile 'io.projectreactor.ipc:reactor-netty'
+	compile 'org.springframework:spring-context'
+	compile 'org.springframework:spring-webflux'
+
+	testCompile 'io.projectreactor.addons:reactor-test'
+	testCompile 'org.skyscreamer:jsonassert'
+	testCompile 'org.springframework:spring-test'
+}

+ 199 - 0
samples/javaconfig/hellowebfluxfn/src/integration-test/java/sample/HelloWebfluxFnApplicationTests.java

@@ -0,0 +1,199 @@
+/*
+ * Copyright 2002-2017 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 sample;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.security.web.server.header.ContentTypeOptionsHttpHeadersWriter;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.reactive.server.ExchangeResult;
+import org.springframework.test.web.reactive.server.WebTestClient;
+import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
+
+import java.nio.charset.Charset;
+import java.time.Duration;
+import java.util.Base64;
+
+import static org.springframework.web.reactive.function.client.ExchangeFilterFunctions.basicAuthentication;
+
+/**
+ * @author Rob Winch
+ * @since 5.0
+ */
+@RunWith(SpringRunner.class)
+@ContextConfiguration(classes = HelloWebfluxFnApplication.class)
+@TestPropertySource(properties = "server.port=0")
+public class HelloWebfluxFnApplicationTests {
+	@Value("#{@nettyContext.address().getPort()}")
+	int port;
+
+	WebTestClient rest;
+
+	@Before
+	public void setup() {
+		this.rest = WebTestClient.bindToServer()
+				.responseTimeout(Duration.ofDays(1))
+				.baseUrl("http://localhost:" + this.port)
+				.build();
+	}
+
+	@Test
+	public void basicRequired() throws Exception {
+		this.rest
+			.get()
+			.uri("/users")
+			.exchange()
+			.expectStatus().isUnauthorized();
+	}
+
+	@Test
+	public void basicWorks() throws Exception {
+		this.rest
+			.filter(robsCredentials())
+			.get()
+			.uri("/users")
+			.exchange()
+			.expectStatus().isOk()
+			.expectBody().json("[{\"id\":null,\"username\":\"rob\",\"password\":\"rob\",\"firstname\":\"Rob\",\"lastname\":\"Winch\"},{\"id\":null,\"username\":\"admin\",\"password\":\"admin\",\"firstname\":\"Admin\",\"lastname\":\"User\"}]");
+	}
+
+	@Test
+	public void basicWhenPasswordInvalid401() throws Exception {
+		this.rest
+			.filter(invalidPassword())
+			.get()
+			.uri("/users")
+			.exchange()
+			.expectStatus().isUnauthorized()
+			.expectBody().isEmpty();
+	}
+
+	@Test
+	public void authorizationAdmin403() throws Exception {
+		this.rest
+			.filter(robsCredentials())
+			.get()
+			.uri("/admin")
+			.exchange()
+			.expectStatus().isEqualTo(HttpStatus.FORBIDDEN)
+			.expectBody().isEmpty();
+	}
+
+	@Test
+	public void authorizationAdmin200() throws Exception {
+		this.rest
+			.filter(adminCredentials())
+			.get()
+			.uri("/admin")
+			.exchange()
+			.expectStatus().isOk();
+	}
+
+	@Test
+	public void basicMissingUser401() throws Exception {
+		this.rest
+			.filter(basicAuthentication("missing-user", "password"))
+			.get()
+			.uri("/admin")
+			.exchange()
+			.expectStatus().isUnauthorized();
+	}
+
+	@Test
+	public void basicInvalidPassword401() throws Exception {
+		this.rest
+			.filter(invalidPassword())
+			.get()
+			.uri("/admin")
+			.exchange()
+			.expectStatus().isUnauthorized();
+	}
+
+	@Test
+	public void basicInvalidParts401() throws Exception {
+		this.rest
+			.get()
+			.uri("/admin")
+			.header("Authorization", "Basic " + base64Encode("no colon"))
+			.exchange()
+			.expectStatus().isUnauthorized();
+	}
+
+	@Test
+	public void sessionWorks() throws Exception {
+		ExchangeResult result = this.rest
+				.filter(robsCredentials())
+				.get()
+				.uri("/users")
+				.exchange()
+				.returnResult(String.class);
+
+		String session = result.getResponseHeaders().getFirst("Set-Cookie");
+
+		this.rest
+			.get()
+			.uri("/users")
+			.header("Cookie", session)
+			.exchange()
+			.expectStatus().isOk();
+	}
+
+	@Test
+	public void principal() throws Exception {
+		this.rest
+			.filter(robsCredentials())
+			.get()
+			.uri("/principal")
+			.exchange()
+			.expectStatus().isOk()
+			.expectBody().json("{\"username\" : \"rob\"}");
+	}
+
+	@Test
+	public void headers() throws Exception {
+		this.rest
+				.filter(robsCredentials())
+				.get()
+				.uri("/principal")
+				.exchange()
+				.expectHeader().valueEquals(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate")
+				.expectHeader().valueEquals(HttpHeaders.EXPIRES, "0")
+				.expectHeader().valueEquals(HttpHeaders.PRAGMA, "no-cache")
+				.expectHeader().valueEquals(ContentTypeOptionsHttpHeadersWriter.X_CONTENT_OPTIONS, ContentTypeOptionsHttpHeadersWriter.NOSNIFF);
+	}
+
+	private ExchangeFilterFunction robsCredentials() {
+		return basicAuthentication("rob","rob");
+	}
+
+	private ExchangeFilterFunction invalidPassword() {
+		return basicAuthentication("rob","INVALID");
+	}
+
+	private ExchangeFilterFunction adminCredentials() {
+		return basicAuthentication("admin","admin");
+	}
+
+	private String base64Encode(String value) {
+		return Base64.getEncoder().encodeToString(value.getBytes(Charset.defaultCharset()));
+	}
+}

+ 51 - 0
samples/javaconfig/hellowebfluxfn/src/integration-test/java/sample/UserRepositoryTests.java

@@ -0,0 +1,51 @@
+/*
+ * Copyright 2002-2017 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 sample;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ *
+ * @author Rob Winch
+ * @since 5.0
+ */
+@SuppressWarnings("unused")
+@RunWith(SpringRunner.class)
+@ContextConfiguration(classes = HelloWebfluxFnApplication.class)
+@TestPropertySource(properties = "server.port=0")
+public class UserRepositoryTests {
+
+	@Autowired UserRepository repository;
+
+	String robUsername = "rob";
+
+	@Test
+	public void findByUsernameWhenUsernameMatchesThenFound() {
+		assertThat(repository.findByUsername(this.robUsername).block()).isNotNull();
+	}
+
+	@Test
+	public void findByUsernameWhenUsernameDoesNotMatchThenFound() {
+		assertThat(repository.findByUsername(this.robUsername + "NOTFOUND").block()).isNull();
+	}
+}

+ 115 - 0
samples/javaconfig/hellowebfluxfn/src/main/java/sample/HelloWebfluxFnApplication.java

@@ -0,0 +1,115 @@
+/*
+ * Copyright 2002-2017 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 sample;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.ReactiveAdapterRegistry;
+import org.springframework.http.server.reactive.HttpHandler;
+import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;
+import org.springframework.security.authentication.ReactiveAuthenticationManager;
+import org.springframework.security.authentication.UserDetailsRepositoryAuthenticationManager;
+import org.springframework.security.authorization.AuthorizationDecision;
+import org.springframework.security.config.web.server.AuthorizeExchangeBuilder;
+import org.springframework.security.config.web.server.HttpSecurity;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.web.reactive.result.method.annotation.AuthenticationPrincipalArgumentResolver;
+import org.springframework.security.web.server.authorization.AuthorizationContext;
+import org.springframework.security.web.server.context.WebSessionSecurityContextRepository;
+import org.springframework.web.reactive.DispatcherHandler;
+import org.springframework.web.reactive.config.EnableWebFlux;
+import org.springframework.web.reactive.config.WebFluxConfigurer;
+import org.springframework.web.reactive.function.server.HandlerStrategies;
+import org.springframework.web.reactive.function.server.RouterFunction;
+import org.springframework.web.reactive.function.server.RouterFunctions;
+import org.springframework.web.reactive.function.server.ServerResponse;
+import org.springframework.web.reactive.result.method.annotation.ArgumentResolverConfigurer;
+import org.springframework.web.server.WebFilter;
+import reactor.core.publisher.Mono;
+import reactor.ipc.netty.NettyContext;
+import reactor.ipc.netty.http.server.HttpServer;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON;
+import static org.springframework.security.config.web.server.HttpSecurity.http;
+import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
+import static org.springframework.web.reactive.function.server.RequestPredicates.accept;
+import static org.springframework.web.reactive.function.server.RequestPredicates.contentType;
+import static org.springframework.web.reactive.function.server.RouterFunctions.route;
+
+/**
+ * @author Rob Winch
+ * @since 5.0
+ */
+@Configuration
+@EnableWebFlux
+@ComponentScan
+public class HelloWebfluxFnApplication {
+	@Value("${server.port:8080}")
+	private int port = 8080;
+
+	public static void main(String[] args) throws Exception {
+		try(AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(HelloWebfluxFnApplication.class)) {
+			context.getBean(NettyContext.class).onClose().block();
+		}
+	}
+
+	@Bean
+	public NettyContext nettyContext(UserController userController, WebFilter springSecurityFilterChain) {
+		RouterFunction<ServerResponse> route = route(
+				GET("/principal"), userController::principal).andRoute(
+				GET("/users"), userController::users).andRoute(
+				GET("/admin"), userController::admin);
+
+		HandlerStrategies handlerStrategies = HandlerStrategies.builder()
+			.webFilter(springSecurityFilterChain).build();
+
+		HttpHandler handler = RouterFunctions.toHttpHandler(route, handlerStrategies);
+		ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(handler);
+		HttpServer httpServer = HttpServer.create("localhost", port);
+		return httpServer.newHandler(adapter).block();
+	}
+
+	@Bean
+	WebFilter springSecurityFilterChain(ReactiveAuthenticationManager manager) throws Exception {
+		HttpSecurity http = http();
+		http.securityContextRepository(new WebSessionSecurityContextRepository());
+		http.authenticationManager(manager);
+		http.httpBasic();
+
+		AuthorizeExchangeBuilder authorize = http.authorizeExchange();
+		authorize.antMatchers("/admin/**").hasRole("ADMIN");
+		authorize.antMatchers("/users/{user}/**").access(this::currentUserMatchesPath);
+		authorize.anyExchange().authenticated();
+		return http.build();
+	}
+
+	private Mono<AuthorizationDecision> currentUserMatchesPath(Mono<Authentication> authentication, AuthorizationContext context) {
+		return authentication
+			.map( a -> context.getVariables().get("user").equals(a.getName()))
+			.map( granted -> new AuthorizationDecision(granted));
+	}
+
+	@Bean
+	public ReactiveAuthenticationManager authenticationManager(UserRepositoryUserDetailsRepository udr) {
+		return new UserDetailsRepositoryAuthenticationManager(udr);
+	}
+}

+ 58 - 0
samples/javaconfig/hellowebfluxfn/src/main/java/sample/MapUserRepository.java

@@ -0,0 +1,58 @@
+/*
+ *
+ *  * Copyright 2002-2017 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 sample;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.springframework.stereotype.Service;
+
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+/**
+ * @author Rob Winch
+ * @since 5.0
+ */
+@Service
+public class MapUserRepository implements UserRepository {
+	private final Map<String,User> users = new HashMap<>();
+
+	public MapUserRepository() {
+		save(new User("rob", "rob", "Rob", "Winch")).block();
+		save(new User("admin", "admin", "Admin", "User")).block();
+	}
+
+	@Override
+	public Flux<User> findAll() {
+		return Flux.fromIterable(users.values());
+	}
+
+	@Override
+	public Mono<User> findByUsername(String username) {
+		User result = users.get(username);
+
+		return result == null ? Mono.empty() : Mono.just(result);
+	}
+
+	public Mono<User> save(User user) {
+		users.put(user.getUsername(), user);
+		return Mono.just(user);
+	}
+}

+ 84 - 0
samples/javaconfig/hellowebfluxfn/src/main/java/sample/User.java

@@ -0,0 +1,84 @@
+/*
+ * Copyright 2002-2017 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 sample;
+
+/**
+ * @author Rob Winch
+ * @since 5.0
+ */
+public class User {
+
+	private Long id;
+	private String username;
+	private String password;
+	private String firstname;
+	private String lastname;
+
+	public User() {}
+
+	public User(User copy) {
+		this(copy.getUsername(), copy.getPassword(), copy.getFirstname(), copy.getLastname());
+	}
+
+	public User(String username, String password, String firstname, String lastname) {
+		super();
+		this.username = username;
+		this.password = password;
+		this.firstname = firstname;
+		this.lastname = lastname;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getUsername() {
+		return username;
+	}
+
+	public void setUsername(String username) {
+		this.username = username;
+	}
+
+	public String getPassword() {
+		return password;
+	}
+
+	public void setPassword(String password) {
+		this.password = password;
+	}
+
+	public String getFirstname() {
+		return firstname;
+	}
+
+	public void setFirstname(String firstname) {
+		this.firstname = firstname;
+	}
+
+	public String getLastname() {
+		return lastname;
+	}
+
+	public void setLastname(String lastname) {
+		this.lastname = lastname;
+	}
+}

+ 65 - 0
samples/javaconfig/hellowebfluxfn/src/main/java/sample/UserController.java

@@ -0,0 +1,65 @@
+/*
+ * Copyright 2002-2017 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 sample;
+
+import org.springframework.http.MediaType;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.web.server.context.SecurityContextRepository;
+import org.springframework.security.web.server.context.WebSessionSecurityContextRepository;
+import org.springframework.stereotype.Component;
+import org.springframework.web.reactive.function.server.ServerRequest;
+import org.springframework.web.reactive.function.server.ServerResponse;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import java.util.Collections;
+import java.util.Map;
+
+/**
+ * @author Rob Winch
+ * @since 5.0
+ */
+@Component
+public class UserController {
+	private final SecurityContextRepository repo = new WebSessionSecurityContextRepository();
+
+	private final UserRepository users;
+
+	public UserController(UserRepository users) {
+		this.users = users;
+	}
+
+	public Mono<ServerResponse> principal(ServerRequest serverRequest) {
+		return serverRequest.principal().cast(Authentication.class).flatMap(p ->
+			ServerResponse.ok()
+				.contentType(MediaType.APPLICATION_JSON)
+				.syncBody(p.getPrincipal()));
+	}
+
+	public Mono<ServerResponse> users(ServerRequest serverRequest) {
+		return ServerResponse.ok()
+			.contentType(MediaType.APPLICATION_JSON)
+			.body(this.users.findAll(), User.class);
+	}
+
+	public Mono<ServerResponse> admin(ServerRequest serverRequest) {
+		return serverRequest.principal().cast(Authentication.class).flatMap(p ->
+			ServerResponse.ok()
+				.contentType(MediaType.APPLICATION_JSON)
+				.syncBody( Collections.singletonMap("isadmin", "true")));
+	}
+}

+ 33 - 0
samples/javaconfig/hellowebfluxfn/src/main/java/sample/UserRepository.java

@@ -0,0 +1,33 @@
+/*
+ * Copyright 2002-2017 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 sample;
+
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+/**
+ *
+ * @author Rob Winch
+ * @since 5.0
+ */
+public interface UserRepository {
+
+	Flux<User> findAll();
+
+	Mono<User> findByUsername(String username);
+
+	Mono<User> save(User user);
+}

+ 87 - 0
samples/javaconfig/hellowebfluxfn/src/main/java/sample/UserRepositoryUserDetailsRepository.java

@@ -0,0 +1,87 @@
+/*
+ * Copyright 2002-2017 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 sample;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.springframework.security.authentication.UserDetailsRepository;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.AuthorityUtils;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.stereotype.Component;
+
+import reactor.core.publisher.Mono;
+
+/**
+ * @author Rob Winch
+ * @since 5.0
+ */
+@Component
+public class UserRepositoryUserDetailsRepository implements UserDetailsRepository {
+	private final UserRepository users;
+
+	public UserRepositoryUserDetailsRepository(UserRepository users) {
+		super();
+		this.users = users;
+	}
+
+	@Override
+	public Mono<UserDetails> findByUsername(String username) {
+		return this.users
+				.findByUsername(username)
+				.map(UserDetailsAdapter::new);
+	}
+
+	@SuppressWarnings("serial")
+	private static class UserDetailsAdapter extends User implements UserDetails {
+		private static List<GrantedAuthority> USER_ROLES = AuthorityUtils.createAuthorityList("ROLE_USER");
+		private static List<GrantedAuthority> ADMIN_ROLES = AuthorityUtils.createAuthorityList("ROLE_ADMIN", "ROLE_USER");
+
+		private UserDetailsAdapter(User delegate) {
+			super(delegate);
+		}
+
+		@Override
+		public Collection<? extends GrantedAuthority> getAuthorities() {
+			return isAdmin() ? ADMIN_ROLES : USER_ROLES ;
+		}
+
+		private boolean isAdmin() {
+			return getUsername().contains("admin");
+		}
+
+		@Override
+		public boolean isAccountNonExpired() {
+			return true;
+		}
+
+		@Override
+		public boolean isAccountNonLocked() {
+			return true;
+		}
+
+		@Override
+		public boolean isCredentialsNonExpired() {
+			return true;
+		}
+
+		@Override
+		public boolean isEnabled() {
+			return true;
+		}
+	}
+}