Skip to content

Commit 74043f0

Browse files
committed
Add actuator endpoint to find and delete sessions
See gh-407
1 parent 6720141 commit 74043f0

File tree

6 files changed

+299
-0
lines changed

6 files changed

+299
-0
lines changed

settings.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,4 @@ include 'spring-session-data-gemfire'
2828
include 'spring-session-data-redis'
2929
include 'spring-session-jdbc'
3030
include 'spring-session-data-mongo'
31+
include 'spring-session-boot'

spring-session-boot/build.gradle

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
buildscript {
2+
repositories {
3+
mavenCentral()
4+
}
5+
dependencies {
6+
classpath("org.springframework.boot:spring-boot-gradle-plugin:$springBootVersion")
7+
}
8+
}
9+
10+
apply from: JAVA_GRADLE
11+
apply plugin: 'spring-io'
12+
13+
description = "Aggregator for Spring Session and Spring Boot"
14+
15+
dependencies {
16+
optional project(':spring-session'),
17+
"org.springframework.boot:spring-boot-actuator:$springBootVersion",
18+
"org.springframework.boot:spring-boot-starter-jdbc:$springBootVersion",
19+
"org.springframework.boot:spring-boot-starter-web:$springBootVersion"
20+
21+
testCompile "org.springframework.boot:spring-boot-starter-test:$springBootVersion",
22+
"com.h2database:h2:$h2Version",
23+
"org.assertj:assertj-core:$assertjVersion"
24+
}
25+
26+
dependencyManagement {
27+
springIoTestRuntime {
28+
imports {
29+
mavenBom "io.spring.platform:platform-bom:${springIoVersion}"
30+
}
31+
}
32+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright 2014-2016 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.session.endpoint;
18+
19+
import org.springframework.boot.actuate.endpoint.Endpoint;
20+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
21+
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
22+
import org.springframework.context.annotation.Bean;
23+
import org.springframework.context.annotation.Configuration;
24+
import org.springframework.session.FindByIndexNameSessionRepository;
25+
26+
/**
27+
* {@link EnableAutoConfiguration Auto-configuration} for session management
28+
* {@link Endpoint}s.
29+
*
30+
* @author Eddú Meléndez
31+
* @since 1.3.0
32+
*/
33+
@Configuration
34+
@ConditionalOnBean(FindByIndexNameSessionRepository.class)
35+
public class EndpointConfiguration {
36+
37+
@Bean
38+
public SessionEndpoint sessionEndpoint() {
39+
return new SessionEndpoint();
40+
}
41+
42+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
* Copyright 2014-2016 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.session.endpoint;
18+
19+
import java.util.Collection;
20+
21+
import org.springframework.beans.factory.annotation.Autowired;
22+
import org.springframework.boot.actuate.endpoint.Endpoint;
23+
import org.springframework.boot.actuate.endpoint.EndpointProperties;
24+
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
25+
import org.springframework.boot.context.properties.ConfigurationProperties;
26+
import org.springframework.context.EnvironmentAware;
27+
import org.springframework.core.env.Environment;
28+
import org.springframework.session.ExpiringSession;
29+
import org.springframework.session.FindByIndexNameSessionRepository;
30+
import org.springframework.web.bind.annotation.PathVariable;
31+
import org.springframework.web.bind.annotation.RequestMapping;
32+
import org.springframework.web.bind.annotation.RequestMethod;
33+
34+
/**
35+
* {@link MvcEndpoint} to expose actuator session.
36+
*
37+
* @author Eddú Meléndez
38+
* @since 1.3.0
39+
*/
40+
@ConfigurationProperties("endpoints.session")
41+
public class SessionEndpoint implements MvcEndpoint, EnvironmentAware {
42+
43+
private Environment environment;
44+
45+
/**
46+
* Endpoint URL path.
47+
*/
48+
private String path = "/session";
49+
50+
/**
51+
* Enable the endpoint.
52+
*/
53+
private boolean enabled = true;
54+
55+
/**
56+
* Mark if the endpoint exposes sensitive information.
57+
*/
58+
private Boolean sensitive;
59+
60+
@Autowired
61+
private FindByIndexNameSessionRepository<? extends ExpiringSession> sessionRepository;
62+
63+
public void setEnvironment(Environment environment) {
64+
this.environment = environment;
65+
}
66+
67+
@RequestMapping(path = "/{username}", method = RequestMethod.GET)
68+
public Collection<? extends ExpiringSession> result(@PathVariable String username) {
69+
return this.sessionRepository.findByIndexNameAndIndexValue(
70+
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, username)
71+
.values();
72+
}
73+
74+
@RequestMapping(path = "/{sessionId}", method = RequestMethod.DELETE)
75+
public void delete(@PathVariable String sessionId) {
76+
this.sessionRepository.delete(sessionId);
77+
}
78+
79+
public void setPath(String path) {
80+
this.path = path;
81+
}
82+
83+
public String getPath() {
84+
return this.path;
85+
}
86+
87+
public void setEnabled(boolean enabled) {
88+
this.enabled = enabled;
89+
}
90+
91+
public boolean isEnabled() {
92+
return this.enabled;
93+
}
94+
95+
public void setSensitive(Boolean sensitive) {
96+
this.sensitive = sensitive;
97+
}
98+
99+
public boolean isSensitive() {
100+
return EndpointProperties.isSensitive(this.environment, this.sensitive, false);
101+
}
102+
103+
public Class<? extends Endpoint> getEndpointType() {
104+
return Endpoint.class;
105+
}
106+
107+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
org.springframework.boot.actuate.autoconfigure.ManagementContextConfiguration=\
2+
org.springframework.session.endpoint.EndpointConfiguration
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/*
2+
* Copyright 2014-2016 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.session.endpoint;
18+
19+
import javax.sql.DataSource;
20+
21+
import org.junit.After;
22+
import org.junit.Test;
23+
24+
import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration;
25+
import org.springframework.boot.actuate.autoconfigure.ManagementServerProperties;
26+
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
27+
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
28+
import org.springframework.boot.test.EnvironmentTestUtils;
29+
import org.springframework.context.annotation.Bean;
30+
import org.springframework.context.annotation.Configuration;
31+
import org.springframework.session.FindByIndexNameSessionRepository;
32+
import org.springframework.session.jdbc.JdbcOperationsSessionRepository;
33+
import org.springframework.transaction.PlatformTransactionManager;
34+
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
35+
36+
import static org.assertj.core.api.Assertions.assertThat;
37+
38+
/**
39+
* Tests for {@link SessionEndpoint}.
40+
*
41+
* @author Eddú Meléndez
42+
*/
43+
public class SessionEndpointTests {
44+
45+
private AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
46+
47+
@After
48+
public void close() {
49+
if (this.context != null) {
50+
this.context.close();
51+
}
52+
}
53+
54+
@Test
55+
public void testCustomProperties() {
56+
this.context.register(EmbeddedDataSourceConfiguration.class,
57+
DataSourceTransactionManagerAutoConfiguration.class,
58+
ManagementServerProperties.class, SessionAutoConfiguration.class,
59+
EndpointConfiguration.class, EndpointWebMvcAutoConfiguration.class);
60+
EnvironmentTestUtils.addEnvironment(this.context, "endpoints.session.path:/mysession",
61+
"endpoints.session.sensitive:true");
62+
this.context.refresh();
63+
SessionEndpoint sessionEndpoint = this.context.getBean(SessionEndpoint.class);
64+
assertThat(sessionEndpoint.getPath()).isEqualTo("/mysession");
65+
assertThat(sessionEndpoint.isSensitive()).isTrue();
66+
assertThat(sessionEndpoint.isEnabled()).isTrue();
67+
}
68+
69+
@Test
70+
public void testEndpointDisabled() {
71+
this.context.register(EmbeddedDataSourceConfiguration.class,
72+
DataSourceTransactionManagerAutoConfiguration.class,
73+
ManagementServerProperties.class, SessionAutoConfiguration.class,
74+
EndpointConfiguration.class, EndpointWebMvcAutoConfiguration.class);
75+
EnvironmentTestUtils.addEnvironment(this.context, "endpoints.session.enabled:false");
76+
this.context.refresh();
77+
SessionEndpoint sessionEndpoint = this.context.getBean(SessionEndpoint.class);
78+
assertThat(sessionEndpoint.isEnabled()).isFalse();
79+
}
80+
81+
@Test
82+
public void testSessionRepositoryIsPresent() {
83+
this.context.register(EmbeddedDataSourceConfiguration.class,
84+
DataSourceTransactionManagerAutoConfiguration.class,
85+
ManagementServerProperties.class, SessionAutoConfiguration.class,
86+
EndpointConfiguration.class, EndpointWebMvcAutoConfiguration.class);
87+
this.context.refresh();
88+
FindByIndexNameSessionRepository sessionRepository = this.context
89+
.getBean(FindByIndexNameSessionRepository.class);
90+
assertThat(sessionRepository).isNotNull();
91+
}
92+
93+
@Test
94+
public void testSessionRepositoryIsNotPresent() {
95+
this.context.register(EmbeddedDataSourceConfiguration.class,
96+
DataSourceTransactionManagerAutoConfiguration.class,
97+
ManagementServerProperties.class, EndpointConfiguration.class,
98+
EndpointWebMvcAutoConfiguration.class);
99+
this.context.refresh();
100+
String[] sessionRepository = this.context
101+
.getBeanNamesForType(FindByIndexNameSessionRepository.class);
102+
assertThat(sessionRepository.length).isEqualTo(0);
103+
}
104+
105+
@Configuration
106+
static class SessionAutoConfiguration {
107+
108+
@Bean
109+
public FindByIndexNameSessionRepository sessionRepository(DataSource dataSource,
110+
PlatformTransactionManager transactionManager) {
111+
return new JdbcOperationsSessionRepository(dataSource, transactionManager);
112+
}
113+
}
114+
115+
}

0 commit comments

Comments
 (0)