Skip to content
This repository was archived by the owner on Dec 12, 2018. It is now read-only.

Commit 9a3c621

Browse files
author
mrioan
authored
Merge pull request #1249 from stormpath/1204_disable.spring_sec.and.stormpath
1204 and 1217: Stormpath and Spring Security disable
2 parents 7be6d0c + cd3d024 commit 9a3c621

File tree

49 files changed

+913
-121
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+913
-121
lines changed

docs/source/quickstart.rst

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ By default, all paths are locked down with Spring Security. Stormpath's Spring S
159159
Disabling Spring Security
160160
"""""""""""""""""""""""""
161161

162-
If you do not want to use our Spring Security integration, set the following two config properties:
162+
If you do not want to use our Spring Security integration, set the following config property:
163163

164164
.. code-block:: yaml
165165
@@ -169,10 +169,18 @@ If you do not want to use our Spring Security integration, set the following two
169169
security:
170170
enabled: false
171171
172-
# disable Spring Security entirely:
173-
security:
174-
basic:
175-
enabled: false
172+
.. note::
173+
174+
Alternatively you can disable Spring Security for good by having the following property in your configuration file:
175+
176+
.. code-block:: yaml
177+
178+
# disable Spring Security altogether:
179+
security:
180+
basic:
181+
enabled: false
182+
183+
This will disable Spring Security along with the Stormpath Spring Security integration.
176184

177185
#end
178186

@@ -232,6 +240,13 @@ Any Problems?
232240

233241
Did you experience any problems with this quickstart? It might not have worked perfectly for you if:
234242

243+
* There might be some cases in which you want to completely turn Stormpath off. For example, if you do not have an ApiKey in
244+
your machine then Stormpath will simply not boot. In those scenarios you can add the following property in the configuration file:
245+
246+
.. code-block:: properties
247+
248+
stormpath.enabled = false
249+
235250
#if( $servlet )
236251

237252
* you have more than one Application registered with Stormpath. If this is the case, you'll need to configure your

docs/source/tutorial.rst

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -240,9 +240,13 @@ disable it. That's where the ``application.properties`` files comes in:
240240
:linenos:
241241
242242
stormpath.spring.security.enabled = false
243-
security.basic.enabled = false
244243
245-
The first line disables Stormpath's hooks into Spring Security and the second line disables Spring Security itself.
244+
That property disables Spring Security and avoids our Spring Security integration to be loaded.
245+
246+
.. note::
247+
Alternatively you can disable the Stormpath Spring Security integration while keeping Spring Security enabled. Such setup will allow you
248+
to take full control of Spring Security's configuration without having Stormath's integration in the mix. This can be
249+
achieved by having `stormpath.spring.security.enabled = false` in your configuration file.
246250

247251
Pretty simple setup, right? In the next section, we'll layer in some flow logic based on logged-in state. And then we
248252
will refine that to make use of all the Spring Security has to offer in making our lives easier.
@@ -895,6 +899,14 @@ As you can see from the examples above, Stormpath provides powerful oauth2 Token
895899
``/oauth/token`` endpoint. There is no additional coding required on your part to make use of the Token Management
896900
feature.
897901

902+
#if( $springboot )
903+
You may notice that there is no class in this part of the tutorial that extends ``WebSecurityConfigurerAdapter``.
904+
In this particular case, *all* user-defined paths are locked down. This is the default for Spring Security and the
905+
Stormpath Spring Security integration follows suit.
906+
907+
If you fire up the tutorial app and browse to the home page: http://localhost:8080/, you will be redirected to `/login`.
908+
#end
909+
898910
.. _wrapping-up:
899911

900912
Wrapping Up

extensions/servlet/src/main/java/com/stormpath/sdk/servlet/config/Config.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ public interface Config extends Map<String, String> {
7878

7979
ControllerConfig getVerifyConfig();
8080

81+
ControllerConfig getSamlConfig();
82+
8183
ChangePasswordConfig getChangePasswordConfig();
8284

8385
Saver<AuthenticationResult> getAuthenticationResultSaver();
@@ -109,6 +111,8 @@ public interface Config extends Map<String, String> {
109111

110112
String getAccessTokenUrl();
111113

114+
String getRevokeTokenUrl();
115+
112116
String getUnauthorizedUrl();
113117

114118
boolean isMeEnabled();

extensions/servlet/src/main/java/com/stormpath/sdk/servlet/config/filter/DefaultFilterChainManagerConfigurer.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,16 @@ public FilterChainManager configure() throws ServletException {
107107
boolean accessTokenChainSpecified = false;
108108
boolean oauthEnabled = config.isOAuthEnabled();
109109

110+
String revokeTokenUrl = config.getRevokeTokenUrl();
111+
String revokeTokenUrlPattern = cleanUri(revokeTokenUrl);
112+
boolean revokeTokenChainSpecified = false;
113+
110114
String unauthorizedUrl = config.getUnauthorizedUrl();
111115
String unauthorizedUrlPattern = cleanUri(unauthorizedUrl);
112116
boolean unauthorizedChainSpecified = false;
113117

114-
//TODO 542: what is this?
115-
String samlUrl = "/saml";
118+
//fixed per https://github.com/stormpath/stormpath-sdk-java/issues/1254
119+
String samlUrl = config.getSamlConfig().getUri();
116120
String samlUrlPattern = cleanUri(samlUrl);
117121
String samlCallbackUrl = config.getCallbackUri();
118122
String samlCallbackPattern = cleanUri(samlCallbackUrl);
@@ -240,6 +244,14 @@ public FilterChainManager configure() throws ServletException {
240244
chainDefinition += Strings.DEFAULT_DELIMITER_CHAR + filterName;
241245
}
242246

247+
} else if (uriPattern.startsWith(revokeTokenUrlPattern)) {
248+
revokeTokenChainSpecified = true;
249+
250+
String filterName = DefaultFilter.revokeToken.name();
251+
if (!chainDefinition.contains(filterName)) {
252+
chainDefinition += Strings.DEFAULT_DELIMITER_CHAR + filterName;
253+
}
254+
243255
} else if (uriPattern.startsWith(unauthorizedUrlPattern)) {
244256
unauthorizedChainSpecified = true;
245257

@@ -321,6 +333,9 @@ public FilterChainManager configure() throws ServletException {
321333
if (!accessTokenChainSpecified && oauthEnabled) {
322334
mgr.createChain(accessTokenUrlPattern, DefaultFilter.accessToken.name());
323335
}
336+
if (!revokeTokenChainSpecified && oauthEnabled) {
337+
mgr.createChain(revokeTokenUrlPattern, DefaultFilter.revokeToken.name());
338+
}
324339
if (!samlChainSpecified && callbackEnabled) {
325340
mgr.createChain(samlUrlPattern, DefaultFilter.saml.name());
326341
mgr.createChain(samlCallbackPattern, DefaultFilter.samlResult.name());

extensions/servlet/src/main/java/com/stormpath/sdk/servlet/config/filter/LoginFilterFactory.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ protected void doConfigure(LoginController controller, Config config) {
4040
controller.setForgotPasswordUri(config.getForgotPasswordConfig().getUri());
4141
controller.setVerifyEnabled(config.getVerifyConfig().isEnabled());
4242
controller.setVerifyUri(config.getVerifyConfig().getUri());
43+
controller.setSamlUri(config.getSamlConfig().getUri());
4344
controller.setRegisterEnabledResolver(config.getRegisterEnabledResolver());
4445
controller.setRegisterUri(config.getRegisterConfig().getUri());
4546
controller.setLogoutUri(config.getLogoutConfig().getUri());
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2017 Stormpath, Inc.
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+
package com.stormpath.sdk.servlet.config.filter;
17+
18+
import com.stormpath.sdk.servlet.config.Config;
19+
import com.stormpath.sdk.servlet.mvc.RevokeTokenController;
20+
21+
/**
22+
* https://github.com/stormpath/stormpath-sdk-java/issues/1247
23+
*
24+
* @since 1.5.0
25+
*/
26+
public class RevokeTokenFilterFactory extends ControllerFilterFactory<RevokeTokenController> {
27+
28+
@Override
29+
protected RevokeTokenController newController() {
30+
return new RevokeTokenController();
31+
}
32+
33+
@Override
34+
protected void configure(RevokeTokenController controller, Config config) throws Exception {
35+
controller.setApplicationResolver(config.getApplicationResolver());
36+
}
37+
}

extensions/servlet/src/main/java/com/stormpath/sdk/servlet/config/impl/DefaultConfig.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ public class DefaultConfig implements Config {
8080
public static final String UNAUTHORIZED_URL = "stormpath.web.unauthorized.uri";
8181
public static final String LOGOUT_INVALIDATE_HTTP_SESSION = "stormpath.web.logout.invalidateHttpSession";
8282
public static final String ACCESS_TOKEN_URL = "stormpath.web.oauth2.uri";
83+
public static final String REVOKE_TOKEN_URL = "stormpath.web.oauth2.revoke.uri";
8384
public static final String ACCESS_TOKEN_VALIDATION_STRATEGY = "stormpath.web.oauth2.password.validationStrategy";
8485

8586
protected static final String SERVER_URI_RESOLVER = "stormpath.web.oauth2.origin.authorizer.serverUriResolver";
@@ -215,6 +216,11 @@ public ControllerConfig getVerifyConfig() {
215216
return new ServletControllerConfig("verifyEmail", this);
216217
}
217218

219+
@Override
220+
public ControllerConfig getSamlConfig() {
221+
return new ServletControllerConfig("saml", this);
222+
}
223+
218224
@Override
219225
public ChangePasswordConfig getChangePasswordConfig() {
220226
return new ChangePasswordServletControllerConfig(this, "changePassword");
@@ -274,6 +280,11 @@ public String getAccessTokenUrl() {
274280
return CFG.getString(ACCESS_TOKEN_URL);
275281
}
276282

283+
@Override
284+
public String getRevokeTokenUrl() {
285+
return CFG.getString(REVOKE_TOKEN_URL);
286+
}
287+
277288
@Override
278289
public String getUnauthorizedUrl() {
279290
return CFG.getString(UNAUTHORIZED_URL);

extensions/servlet/src/main/java/com/stormpath/sdk/servlet/event/TokenRevocationRequestEventListener.java

Lines changed: 23 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,28 @@
1515
*/
1616
package com.stormpath.sdk.servlet.event;
1717

18+
import com.stormpath.sdk.application.Application;
1819
import com.stormpath.sdk.client.Client;
1920
import com.stormpath.sdk.impl.ds.InternalDataStore;
21+
import com.stormpath.sdk.impl.error.DefaultError;
22+
import com.stormpath.sdk.lang.Strings;
2023
import com.stormpath.sdk.oauth.AccessToken;
24+
import com.stormpath.sdk.oauth.OAuthRequests;
25+
import com.stormpath.sdk.oauth.OAuthRevocationRequest;
26+
import com.stormpath.sdk.oauth.OAuthRevocationRequestBuilder;
27+
import com.stormpath.sdk.oauth.OAuthTokenRevocators;
2128
import com.stormpath.sdk.oauth.RefreshToken;
29+
import com.stormpath.sdk.oauth.TokenTypeHint;
2230
import com.stormpath.sdk.resource.ResourceException;
2331
import com.stormpath.sdk.servlet.account.event.RegisteredAccountRequestEvent;
2432
import com.stormpath.sdk.servlet.account.event.VerifiedAccountRequestEvent;
33+
import com.stormpath.sdk.servlet.application.ApplicationResolver;
2534
import com.stormpath.sdk.servlet.authc.FailedAuthenticationRequestEvent;
2635
import com.stormpath.sdk.servlet.authc.LogoutRequestEvent;
2736
import com.stormpath.sdk.servlet.authc.SuccessfulAuthenticationRequestEvent;
2837
import com.stormpath.sdk.servlet.client.ClientResolver;
38+
import com.stormpath.sdk.servlet.filter.oauth.OAuthErrorCode;
39+
import com.stormpath.sdk.servlet.filter.oauth.OAuthException;
2940
import com.stormpath.sdk.servlet.http.CookieResolver;
3041
import com.stormpath.sdk.servlet.oauth.impl.JwtTokenSigningKeyResolver;
3142
import io.jsonwebtoken.Claims;
@@ -37,6 +48,7 @@
3748
import org.slf4j.Logger;
3849
import org.slf4j.LoggerFactory;
3950

51+
import javax.servlet.http.HttpServletRequest;
4052
import java.security.Key;
4153
import java.util.LinkedHashMap;
4254
import java.util.Map;
@@ -51,9 +63,7 @@ public class TokenRevocationRequestEventListener implements RequestEventListener
5163
private final TokenExtractor tokenExtractor = new BearerHeaderTokenExtractor();
5264
private final CookieResolver accessTokenCookieResolver = new CookieResolver("access_token");
5365

54-
private final JwtTokenSigningKeyResolver jwtTokenSigningKeyResolver = new JwtTokenSigningKeyResolver();
55-
56-
private Client client = null;
66+
protected ApplicationResolver applicationResolver = ApplicationResolver.INSTANCE;
5767

5868
@Override
5969
public void on(SuccessfulAuthenticationRequestEvent event) {
@@ -78,30 +88,17 @@ public void on(VerifiedAccountRequestEvent event) {
7888
@Override
7989
public void on(LogoutRequestEvent event) {
8090
String jwt = getJwtFromLogoutRequestEvent(event);
81-
if (jwt != null) {
82-
if (this.client == null) {
83-
this.client = ClientResolver.INSTANCE.getClient(event.getRequest()); //will throw if not found
84-
}
85-
86-
Key signingKey = jwtTokenSigningKeyResolver.getSigningKey(event.getRequest(), event.getResponse(), null, SignatureAlgorithm.HS256);
87-
JwsHeader header = Jwts.parser().setSigningKey(signingKey.getEncoded()).parseClaimsJws(jwt).getHeader();
88-
Claims claims = Jwts.parser().setSigningKey(signingKey.getEncoded()).parseClaimsJws(jwt).getBody();
89-
90-
//Let's be sure this jwt is actually an access token otherwise we will have an error when trying to retrieve
91-
//a resource (in order to delete it) that actually is not what we expect
92-
if (isAccessToken(header)) {
93-
gracefullyDeleteRefreshToken((String) claims.get("rti"));
94-
gracefullyDeleteAccessToken(claims.getId());
91+
HttpServletRequest request = event.getRequest();
92+
Application application = applicationResolver.getApplication(request);
93+
if (application != null && jwt != null) {
94+
try {
95+
OAuthRevocationRequest revocationRequest = OAuthRequests.OAUTH_TOKEN_REVOCATION_REQUEST.builder().setToken(jwt).build();
96+
OAuthTokenRevocators.OAUTH_TOKEN_REVOCATOR.forApplication(application).revoke(revocationRequest);
97+
} catch (ResourceException e) {
98+
com.stormpath.sdk.error.Error error = e.getStormpathError();
99+
String message = error.getMessage();
100+
log.warn("There was an error trying to revoke a token", message);
95101
}
96-
//There should never be a refresh token here. Therefore we will not even try to identify if the received JWT is
97-
//a refresh token. That would be a bug in the filter chain as a refresh token should never be used to anything other than
98-
//obtaining a new access token
99-
100-
//Fix for https://github.com/stormpath/stormpath-sdk-java/issues/611
101-
log.debug(
102-
"The current access and refresh tokens for '{}' have been revoked.",
103-
(event.getAccount() != null) ? event.getAccount().getEmail() : "unknown user"
104-
);
105102
}
106103
}
107104

@@ -117,34 +114,4 @@ protected String getJwtFromLogoutRequestEvent(LogoutRequestEvent event) {
117114
return jwt;
118115
}
119116

120-
private boolean isAccessToken(JwsHeader header) {
121-
return header.get("stt").equals("access");
122-
}
123-
124-
private void gracefullyDeleteAccessToken(String accessTokenId) {
125-
try {
126-
String href = "/accessTokens/" + accessTokenId;
127-
Map<String, Object> map = new LinkedHashMap<String, Object>();
128-
map.put("href", href);
129-
AccessToken accessToken = ((InternalDataStore)client.getDataStore()).instantiate(AccessToken.class, map, true);
130-
accessToken.delete();
131-
} catch (ResourceException e) {
132-
//Let's prevent an error to allow the flow to continue
133-
log.warn("There was an error trying to delete access token with ID {}", accessTokenId, e);
134-
}
135-
}
136-
137-
private void gracefullyDeleteRefreshToken(String refreshTokenId) {
138-
try{
139-
String href = "/refreshTokens/" + refreshTokenId;
140-
Map<String, Object> map = new LinkedHashMap<String, Object>();
141-
map.put("href", href);
142-
RefreshToken refreshToken = ((InternalDataStore)client.getDataStore()).instantiate(RefreshToken.class, map, true);
143-
refreshToken.delete();
144-
} catch (ResourceException e) {
145-
//Let's prevent an error to allow the flow to continue, this component is basically a listener that tries to delete
146-
//the current access and refresh tokens on logout, we will only post this error in the log
147-
log.warn("There was an error trying to delete refresh token with ID {}", refreshTokenId, e);
148-
}
149-
}
150117
}

extensions/servlet/src/main/java/com/stormpath/sdk/servlet/filter/DefaultFilter.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import com.stormpath.sdk.servlet.config.filter.LogoutFilterFactory;
3535
import com.stormpath.sdk.servlet.config.filter.MeFilterFactory;
3636
import com.stormpath.sdk.servlet.config.filter.RegisterFilterFactory;
37+
import com.stormpath.sdk.servlet.config.filter.RevokeTokenFilterFactory;
3738
import com.stormpath.sdk.servlet.config.filter.SamlFilterFactory;
3839
import com.stormpath.sdk.servlet.config.filter.SamlResultFilterFactory;
3940
import com.stormpath.sdk.servlet.config.filter.StaticResourceFilterFactory;
@@ -51,6 +52,7 @@
5152
public enum DefaultFilter {
5253

5354
accessToken(ControllerFilter.class, AccessTokenFilterFactory.class),
55+
revokeToken(ControllerFilter.class, RevokeTokenFilterFactory.class),
5456
account(AccountAuthorizationFilter.class, AccountAuthorizationFilterFactory.class),
5557
anon(AnonymousFilter.class, null),
5658
authc(AuthenticationFilter.class, AuthenticationFilterFactory.class),

extensions/servlet/src/main/java/com/stormpath/sdk/servlet/mvc/LoginController.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ public class LoginController extends FormController {
5050
private String verifyUri;
5151
private String registerUri;
5252
private String logoutUri;
53+
private String samlUri;
5354
private boolean verifyEnabled = true;
5455
private boolean forgotPasswordEnabled = true;
5556
private boolean idSiteEnabled;
@@ -79,6 +80,10 @@ public void setLogoutUri(String logoutUri) {
7980
this.logoutUri = logoutUri;
8081
}
8182

83+
public void setSamlUri(String samlUri) {
84+
this.samlUri = samlUri;
85+
}
86+
8287
public void setVerifyEnabled(boolean verifyEnabled) {
8388
this.verifyEnabled = verifyEnabled;
8489
}
@@ -149,6 +154,7 @@ public void init() throws Exception {
149154
Assert.hasText(this.registerUri, "registerUri property cannot be null or empty.");
150155
Assert.notNull(this.registerEnabledResolver, "registerEnabledResolver cannot be null.");
151156
Assert.hasText(this.logoutUri, "logoutUri property cannot be null or empty.");
157+
Assert.hasText(this.samlUri, "samlUri property cannot be null or empty.");
152158
Assert.notNull(this.authenticationResultSaver, "authenticationResultSaver property cannot be null.");
153159
Assert.notNull(this.errorModelFactory, "errorModelFactory cannot be null.");
154160
Assert.notNull(this.preLoginHandler, "preLoginHandler cannot be null.");
@@ -193,6 +199,7 @@ protected void appendModel(HttpServletRequest request, HttpServletResponse respo
193199
model.put("verifyUri", verifyUri);
194200
model.put("registerEnabled", registerEnabledResolver.get(request, response));
195201
model.put("registerUri", registerUri);
202+
model.put("samlUri", samlUri);
196203
model.put("oauthStateToken", UUID.randomUUID().toString());
197204
String status = request.getParameter("status");
198205
if (status != null) {

0 commit comments

Comments
 (0)