Merge pull request #133 from Doha2012/master

add exception handler
This commit is contained in:
Eugen 2015-02-12 14:29:28 +02:00
commit 6f9cf4368f
26 changed files with 810 additions and 66 deletions

View File

@ -1,28 +0,0 @@
package org.baeldung.web;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.client.RestOperations;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
@Controller
public class RedditController {
private RestOperations redditRestTemplate;
@RequestMapping("/reddit/info")
public String getInfo(Model model) throws Exception {
String result = redditRestTemplate.getForObject("https://oauth.reddit.com/api/v1/me", String.class);
JsonNode node = new ObjectMapper().readTree(result);
model.addAttribute("info", node.get("name").asText());
return "reddit";
}
public void setRedditRestTemplate(RestOperations redditRestTemplate) {
this.redditRestTemplate = redditRestTemplate;
}
}

View File

@ -19,6 +19,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.MessageSource;
import org.springframework.http.MediaType;
import org.springframework.mail.MailAuthenticationException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
@ -35,6 +36,7 @@ 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.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
@Controller
@ -121,7 +123,6 @@ public class RegistrationController {
public String resendRegistrationToken(final HttpServletRequest request, final Model model, @RequestParam("token") final String existingToken) {
final Locale locale = request.getLocale();
final VerificationToken newToken = userService.generateNewVerificationToken(existingToken);
final User user = userService.getUser(newToken.getToken());
try {
final String appUrl = request.getServerName() + ":" + request.getServerPort() + request.getContextPath();
@ -135,32 +136,19 @@ public class RegistrationController {
model.addAttribute("message", e.getLocalizedMessage());
return "redirect:/login.html?lang=" + locale.getLanguage();
}
model.addAttribute("message", messages.getMessage("message.resendToken", null, locale));
return "redirect:/login.html?lang=" + locale.getLanguage();
}
@RequestMapping(value = "/user/resendRegistrationToken2", method = RequestMethod.GET)
public String resendRegistrationToken2(final HttpServletRequest request, final Model model, @RequestParam("token") final String existingToken) {
final Locale locale = request.getLocale();
@RequestMapping(value = "/user/resendRegistrationToken2", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody String resendRegistrationToken2(final HttpServletRequest request, final Model model, @RequestParam("token") final String existingToken) {
final VerificationToken newToken = userService.generateNewVerificationToken(existingToken);
final User user = userService.getUser(newToken.getToken());
try {
final String appUrl = request.getServerName() + ":" + request.getServerPort() + request.getContextPath();
final SimpleMailMessage email = constructResetVerificationTokenEmail(appUrl, request.getLocale(), newToken, user);
mailSender.send(email);
} catch (final MailAuthenticationException e) {
LOGGER.debug("MailAuthenticationException", e);
return "redirect:/emailError.html?lang=" + locale.getLanguage();
} catch (final Exception e) {
LOGGER.debug(e.getLocalizedMessage(), e);
model.addAttribute("message", e.getLocalizedMessage());
return "redirect:/login.html?lang=" + locale.getLanguage();
}
model.addAttribute("message", messages.getMessage("message.resendToken", null, locale));
return "redirect:/login.html?lang=" + locale.getLanguage();
final String appUrl = request.getServerName() + ":" + request.getServerPort() + request.getContextPath();
final SimpleMailMessage email = constructResetVerificationTokenEmail(appUrl, request.getLocale(), newToken, user);
System.out.println(email.getText());
mailSender.send(email);
return messages.getMessage("message.resendToken", null, request.getLocale());
}
@RequestMapping(value = "/user/resetPassword", method = RequestMethod.POST)

View File

@ -0,0 +1,35 @@
package org.baeldung.web.error;
import org.springframework.mail.MailAuthenticationException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
@ControllerAdvice
public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
public RestResponseEntityExceptionHandler() {
super();
}
// API
// 500
@ExceptionHandler({ MailAuthenticationException.class })
public @ResponseBody String handleMail(final RuntimeException ex, final WebRequest request) throws JsonProcessingException {
logger.error("500 Status Code", ex);
return new ObjectMapper().writeValueAsString(ex.getClass().toString());
}
@ExceptionHandler({ NullPointerException.class, IllegalArgumentException.class, IllegalStateException.class })
public @ResponseBody String handleInternal(final RuntimeException ex, final WebRequest request) throws JsonProcessingException {
logger.error("500 Status Code", ex);
return new ObjectMapper().writeValueAsString(ex.getClass().toString());
}
}

View File

@ -1,6 +1,6 @@
################### DataSource Configuration ##########################
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/registration_02?createDatabaseIfNotExist=true
jdbc.url=jdbc:mysql://localhost:3606/registration_02?createDatabaseIfNotExist=true
jdbc.user=tutorialuser
jdbc.pass=tutorialmy5ql
init-db=false

View File

@ -23,12 +23,28 @@ code="label.form.loginSignUp"></spring:message></a>
<c:if test="${param.expired}">
<br>
<h1>${label.form.resendRegistrationToken}</h1>
<a href="<c:url value="/user/resendRegistrationToken">
<c:param name="token" value="${param.token}"/>
</c:url>">
<button onclick="resendToken()">
<spring:message code="label.form.resendRegistrationToken"></spring:message>
</a>
</c:if>
</button>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script type="text/javascript">
function resendToken(){
$.get("<c:url value="/user/resendRegistrationToken2"><c:param name="token" value="${param.token}"/></c:url>", function(data){
if(data.indexOf("MailAuthenticationException") > -1)
{
window.location.href = "<c:url value="/emailError.html"></c:url>";
}
else if(data.indexOf("Exception") > -1){
window.location.href = "<c:url value="/login"><c:param name="message" value="Error"/></c:url>";
}
else{
window.location.href = "<c:url value="/login"></c:url>" + "message=" + data;
}
});
}
</script>
</c:if>
</body>
</html>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>spring-oauth</name>
<name>spring-security-oauth</name>
<comment></comment>
<projects>
</projects>

View File

@ -1,10 +1,10 @@
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.baeldung</groupId>
<artifactId>spring-oauth</artifactId>
<artifactId>spring-security-oauth</artifactId>
<version>0.1-SNAPSHOT</version>
<name>spring-oauth</name>
<name>spring-security-oauth</name>
<packaging>war</packaging>
<dependencies>
@ -251,7 +251,7 @@
</dependencies>
<build>
<finalName>spring-oauth</finalName>
<finalName>spring-security-oauth</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>

View File

@ -0,0 +1,134 @@
package org.baeldung.config;
import java.util.Collections;
import java.util.List;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.client.resource.OAuth2AccessDeniedException;
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.client.resource.UserRedirectRequiredException;
import org.springframework.security.oauth2.client.token.AccessTokenProvider;
import org.springframework.security.oauth2.client.token.AccessTokenRequest;
import org.springframework.security.oauth2.client.token.ClientTokenServices;
import org.springframework.security.oauth2.client.token.OAuth2AccessTokenSupport;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
public class MyAccessTokenProviderChain extends OAuth2AccessTokenSupport implements AccessTokenProvider {
private final List<AccessTokenProvider> chain;
private ClientTokenServices clientTokenServices;
public MyAccessTokenProviderChain(List<? extends AccessTokenProvider> chain) {
this.chain = chain == null ? Collections.<AccessTokenProvider> emptyList() : Collections.unmodifiableList(chain);
}
public void setClientTokenServices(ClientTokenServices clientTokenServices) {
this.clientTokenServices = clientTokenServices;
}
public boolean supportsResource(OAuth2ProtectedResourceDetails resource) {
for (AccessTokenProvider tokenProvider : chain) {
if (tokenProvider.supportsResource(resource)) {
return true;
}
}
return false;
}
public boolean supportsRefresh(OAuth2ProtectedResourceDetails resource) {
for (AccessTokenProvider tokenProvider : chain) {
if (tokenProvider.supportsRefresh(resource)) {
return true;
}
}
return false;
}
public OAuth2AccessToken obtainAccessToken(OAuth2ProtectedResourceDetails resource, AccessTokenRequest request) throws UserRedirectRequiredException, AccessDeniedException {
System.out.println("Obtain new token=====");
OAuth2AccessToken accessToken = null;
OAuth2AccessToken existingToken = null;
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
System.out.println("The authentication is ---- " + auth);
if (auth instanceof AnonymousAuthenticationToken) {
if (!resource.isClientOnly()) {
throw new InsufficientAuthenticationException("Authentication is required to obtain an access token (anonymous not allowed)");
}
}
if (resource.isClientOnly() || (auth != null && auth.isAuthenticated())) {
existingToken = request.getExistingToken();
System.out.println("checking existing token =====");
if (existingToken == null && clientTokenServices != null) {
System.out.println("get existing token from clientTokenServices ==== ");
existingToken = clientTokenServices.getAccessToken(resource, auth);
}
if (existingToken != null) {
if (existingToken.isExpired()) {
System.out.println("expired token");
if (clientTokenServices != null) {
clientTokenServices.removeAccessToken(resource, auth);
}
OAuth2RefreshToken refreshToken = existingToken.getRefreshToken();
if (refreshToken != null) {
System.out.println("let's refresh it");
accessToken = refreshAccessToken(resource, refreshToken, request);
}
} else {
System.out.println("use existing because not expired yet");
accessToken = existingToken;
}
}
}
if (accessToken == null) {
System.out.println("no token so let get it");
accessToken = obtainNewAccessTokenInternal(resource, request);
if (accessToken == null) {
throw new IllegalStateException("An OAuth 2 access token must be obtained or an exception thrown.");
}
}
if (clientTokenServices != null && auth != null && auth.isAuthenticated()) {
clientTokenServices.saveAccessToken(resource, auth, accessToken);
}
return accessToken;
}
protected OAuth2AccessToken obtainNewAccessTokenInternal(OAuth2ProtectedResourceDetails details, AccessTokenRequest request) throws UserRedirectRequiredException, AccessDeniedException {
if (request.isError()) {
throw OAuth2Exception.valueOf(request.toSingleValueMap());
}
for (AccessTokenProvider tokenProvider : chain) {
if (tokenProvider.supportsResource(details)) {
System.out.println("we will use this provider to get it => " + tokenProvider.getClass().getName());
return tokenProvider.obtainAccessToken(details, request);
}
}
throw new OAuth2AccessDeniedException("Unable to obtain a new access token for resource '" + details.getId() + "'. The provider manager is not configured to support it.", details);
}
public OAuth2AccessToken refreshAccessToken(OAuth2ProtectedResourceDetails resource, OAuth2RefreshToken refreshToken, AccessTokenRequest request) throws UserRedirectRequiredException {
for (AccessTokenProvider tokenProvider : chain) {
if (tokenProvider.supportsRefresh(resource)) {
System.out.println("we will use this provider to refresh it => " + tokenProvider.getClass().getName());
return tokenProvider.refreshAccessToken(resource, refreshToken, request);
}
}
throw new OAuth2AccessDeniedException("Unable to obtain a new access token for resource '" + resource.getId() + "'. The provider manager is not configured to support it.", resource);
}
}

View File

@ -0,0 +1,295 @@
package org.baeldung.config;
import java.io.IOException;
import java.net.URI;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.oauth2.client.filter.state.DefaultStateKeyGenerator;
import org.springframework.security.oauth2.client.filter.state.StateKeyGenerator;
import org.springframework.security.oauth2.client.resource.OAuth2AccessDeniedException;
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.client.resource.UserApprovalRequiredException;
import org.springframework.security.oauth2.client.resource.UserRedirectRequiredException;
import org.springframework.security.oauth2.client.token.AccessTokenProvider;
import org.springframework.security.oauth2.client.token.AccessTokenRequest;
import org.springframework.security.oauth2.client.token.DefaultRequestEnhancer;
import org.springframework.security.oauth2.client.token.RequestEnhancer;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
import org.springframework.security.oauth2.common.exceptions.InvalidRequestException;
import org.springframework.security.oauth2.common.util.OAuth2Utils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.ResponseExtractor;
public class MyAuthorizationCodeAccessTokenProvider extends AuthorizationCodeAccessTokenProvider implements AccessTokenProvider {
private StateKeyGenerator stateKeyGenerator = new DefaultStateKeyGenerator();
private String scopePrefix = OAuth2Utils.SCOPE_PREFIX;
private RequestEnhancer authorizationRequestEnhancer = new DefaultRequestEnhancer();
@Override
public void setAuthorizationRequestEnhancer(RequestEnhancer authorizationRequestEnhancer) {
this.authorizationRequestEnhancer = authorizationRequestEnhancer;
}
@Override
public void setScopePrefix(String scopePrefix) {
this.scopePrefix = scopePrefix;
}
@Override
public void setStateKeyGenerator(StateKeyGenerator stateKeyGenerator) {
this.stateKeyGenerator = stateKeyGenerator;
}
@Override
public boolean supportsResource(OAuth2ProtectedResourceDetails resource) {
return resource instanceof AuthorizationCodeResourceDetails && "authorization_code".equals(resource.getGrantType());
}
@Override
public boolean supportsRefresh(OAuth2ProtectedResourceDetails resource) {
return supportsResource(resource);
}
@Override
public String obtainAuthorizationCode(OAuth2ProtectedResourceDetails details, AccessTokenRequest request) throws UserRedirectRequiredException, UserApprovalRequiredException, AccessDeniedException, OAuth2AccessDeniedException {
AuthorizationCodeResourceDetails resource = (AuthorizationCodeResourceDetails) details;
HttpHeaders headers = getHeadersForAuthorizationRequest(request);
MultiValueMap<String, String> form = new LinkedMultiValueMap<String, String>();
if (request.containsKey(OAuth2Utils.USER_OAUTH_APPROVAL)) {
form.set(OAuth2Utils.USER_OAUTH_APPROVAL, request.getFirst(OAuth2Utils.USER_OAUTH_APPROVAL));
for (String scope : details.getScope()) {
form.set(scopePrefix + scope, request.getFirst(OAuth2Utils.USER_OAUTH_APPROVAL));
}
} else {
form.putAll(getParametersForAuthorizeRequest(resource, request));
}
form.set("duration", "permanent");
authorizationRequestEnhancer.enhance(request, resource, form, headers);
final AccessTokenRequest copy = request;
final ResponseExtractor<ResponseEntity<Void>> delegate = getAuthorizationResponseExtractor();
ResponseExtractor<ResponseEntity<Void>> extractor = new ResponseExtractor<ResponseEntity<Void>>() {
@Override
public ResponseEntity<Void> extractData(ClientHttpResponse response) throws IOException {
if (response.getHeaders().containsKey("Set-Cookie")) {
copy.setCookie(response.getHeaders().getFirst("Set-Cookie"));
}
return delegate.extractData(response);
}
};
ResponseEntity<Void> response = getRestTemplate().execute(resource.getUserAuthorizationUri(), HttpMethod.POST, getRequestCallback(resource, form, headers), extractor, form.toSingleValueMap());
if (response.getStatusCode() == HttpStatus.OK) {
throw getUserApprovalSignal(resource, request);
}
URI location = response.getHeaders().getLocation();
String query = location.getQuery();
Map<String, String> map = OAuth2Utils.extractMap(query);
if (map.containsKey("state")) {
request.setStateKey(map.get("state"));
if (request.getPreservedState() == null) {
String redirectUri = resource.getRedirectUri(request);
if (redirectUri != null) {
request.setPreservedState(redirectUri);
} else {
request.setPreservedState(new Object());
}
}
}
String code = map.get("code");
if (code == null) {
throw new UserRedirectRequiredException(location.toString(), form.toSingleValueMap());
}
request.set("code", code);
return code;
}
@Override
protected ResponseExtractor<ResponseEntity<Void>> getAuthorizationResponseExtractor() {
return new ResponseExtractor<ResponseEntity<Void>>() {
public ResponseEntity<Void> extractData(ClientHttpResponse response) throws IOException {
return new ResponseEntity<Void>(response.getHeaders(), response.getStatusCode());
}
};
}
@Override
public OAuth2AccessToken obtainAccessToken(OAuth2ProtectedResourceDetails details, AccessTokenRequest request) throws UserRedirectRequiredException, UserApprovalRequiredException, AccessDeniedException, OAuth2AccessDeniedException {
AuthorizationCodeResourceDetails resource = (AuthorizationCodeResourceDetails) details;
if (request.getAuthorizationCode() == null) {
if (request.getStateKey() == null) {
throw getRedirectForAuthorization(resource, request);
}
obtainAuthorizationCode(resource, request);
}
return retrieveToken(request, resource, getParametersForTokenRequest(resource, request), getHeadersForTokenRequest(request));
}
@Override
public OAuth2AccessToken refreshAccessToken(OAuth2ProtectedResourceDetails resource, OAuth2RefreshToken refreshToken, AccessTokenRequest request) throws UserRedirectRequiredException, OAuth2AccessDeniedException {
MultiValueMap<String, String> form = new LinkedMultiValueMap<String, String>();
form.add("grant_type", "refresh_token");
form.add("refresh_token", refreshToken.getValue());
try {
return retrieveToken(request, resource, form, getHeadersForTokenRequest(request));
} catch (OAuth2AccessDeniedException e) {
throw getRedirectForAuthorization((AuthorizationCodeResourceDetails) resource, request);
}
}
private HttpHeaders getHeadersForTokenRequest(AccessTokenRequest request) {
HttpHeaders headers = new HttpHeaders();
// No cookie for token request
return headers;
}
private HttpHeaders getHeadersForAuthorizationRequest(AccessTokenRequest request) {
HttpHeaders headers = new HttpHeaders();
headers.putAll(request.getHeaders());
if (request.getCookie() != null) {
headers.set("Cookie", request.getCookie());
}
return headers;
}
private MultiValueMap<String, String> getParametersForTokenRequest(AuthorizationCodeResourceDetails resource, AccessTokenRequest request) {
MultiValueMap<String, String> form = new LinkedMultiValueMap<String, String>();
form.set("grant_type", "authorization_code");
form.set("code", request.getAuthorizationCode());
Object preservedState = request.getPreservedState();
if (request.getStateKey() != null) {
if (preservedState == null) {
throw new InvalidRequestException("Possible CSRF detected - state parameter was present but no state could be found");
}
}
String redirectUri = null;
if (preservedState instanceof String) {
redirectUri = String.valueOf(preservedState);
} else {
redirectUri = resource.getRedirectUri(request);
}
if (redirectUri != null && !"NONE".equals(redirectUri)) {
form.set("redirect_uri", redirectUri);
}
return form;
}
private MultiValueMap<String, String> getParametersForAuthorizeRequest(AuthorizationCodeResourceDetails resource, AccessTokenRequest request) {
MultiValueMap<String, String> form = new LinkedMultiValueMap<String, String>();
form.set("response_type", "code");
form.set("client_id", resource.getClientId());
if (request.get("scope") != null) {
form.set("scope", request.getFirst("scope"));
} else {
form.set("scope", OAuth2Utils.formatParameterList(resource.getScope()));
}
String redirectUri = resource.getPreEstablishedRedirectUri();
Object preservedState = request.getPreservedState();
if (redirectUri == null && preservedState != null) {
redirectUri = String.valueOf(preservedState);
} else {
redirectUri = request.getCurrentUri();
}
String stateKey = request.getStateKey();
if (stateKey != null) {
form.set("state", stateKey);
if (preservedState == null) {
throw new InvalidRequestException("Possible CSRF detected - state parameter was present but no state could be found");
}
}
if (redirectUri != null) {
form.set("redirect_uri", redirectUri);
}
return form;
}
private UserRedirectRequiredException getRedirectForAuthorization(AuthorizationCodeResourceDetails resource, AccessTokenRequest request) {
// we don't have an authorization code yet. So first get that.
TreeMap<String, String> requestParameters = new TreeMap<String, String>();
requestParameters.put("response_type", "code"); // oauth2 spec, section 3
requestParameters.put("client_id", resource.getClientId());
requestParameters.put("duration", "permanent");
// Client secret is not required in the initial authorization request
String redirectUri = resource.getRedirectUri(request);
if (redirectUri != null) {
requestParameters.put("redirect_uri", redirectUri);
}
if (resource.isScoped()) {
StringBuilder builder = new StringBuilder();
List<String> scope = resource.getScope();
if (scope != null) {
Iterator<String> scopeIt = scope.iterator();
while (scopeIt.hasNext()) {
builder.append(scopeIt.next());
if (scopeIt.hasNext()) {
builder.append(' ');
}
}
}
requestParameters.put("scope", builder.toString());
}
UserRedirectRequiredException redirectException = new UserRedirectRequiredException(resource.getUserAuthorizationUri(), requestParameters);
String stateKey = stateKeyGenerator.generateKey(resource);
redirectException.setStateKey(stateKey);
request.setStateKey(stateKey);
redirectException.setStateToPreserve(redirectUri);
request.setPreservedState(redirectUri);
return redirectException;
}
protected UserApprovalRequiredException getUserApprovalSignal(AuthorizationCodeResourceDetails resource, AccessTokenRequest request) {
String message = String.format("Do you approve the client '%s' to access your resources with scope=%s", resource.getClientId(), resource.getScope());
return new UserApprovalRequiredException(resource.getUserAuthorizationUri(), Collections.singletonMap(OAuth2Utils.USER_OAUTH_APPROVAL, message), resource.getClientId(), resource.getScope());
}
}

View File

@ -0,0 +1,76 @@
package org.baeldung.config;
import java.util.Properties;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@EnableTransactionManagement
@PropertySource({ "classpath:persistence.properties" })
@ComponentScan({ "org.baeldung.persistence" })
@EnableJpaRepositories(basePackages = "org.baeldung.persistence.dao")
public class PersistenceJPAConfig {
@Autowired
private Environment env;
public PersistenceJPAConfig() {
super();
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan(new String[] { "org.baeldung.persistence.model" });
final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
return em;
}
@Bean
public DataSource dataSource() {
final DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
dataSource.setUrl(env.getProperty("jdbc.url"));
dataSource.setUsername(env.getProperty("jdbc.user"));
dataSource.setPassword(env.getProperty("jdbc.pass"));
return dataSource;
}
@Bean
public JpaTransactionManager transactionManager() {
final JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
@Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
final Properties additionalProperties() {
final Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect"));
return hibernateProperties;
}
}

View File

@ -0,0 +1,53 @@
package org.baeldung.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
@Configuration
@EnableWebSecurity
@ComponentScan(basePackages = { "org.baeldung.security" })
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Bean
public DaoAuthenticationProvider authProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService);
return authProvider;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authProvider());
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/resources/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http.anonymous().disable().authorizeRequests()
.antMatchers("/**").permitAll()
.antMatchers("/reddit","/reddit/**").hasRole("User");
// .and()
// .formLogin()
// .loginPage("/login")
// .permitAll();
// @formatter:on
}
}

View File

@ -13,7 +13,7 @@ public class ServletInitializer extends AbstractDispatcherServletInitializer {
@Override
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(WebConfig.class);
context.register(PersistenceJPAConfig.class, SecurityConfig.class, WebConfig.class);
return context;
}
@ -31,6 +31,7 @@ public class ServletInitializer extends AbstractDispatcherServletInitializer {
public void onStartup(ServletContext servletContext) throws ServletException {
super.onStartup(servletContext);
registerProxyFilter(servletContext, "oauth2ClientContextFilter");
// registerProxyFilter(servletContext, "springSecurityFilterChain");
}
private void registerProxyFilter(ServletContext servletContext, String name) {

View File

@ -12,9 +12,12 @@ import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.security.oauth2.client.OAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.client.token.AccessTokenProvider;
import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsAccessTokenProvider;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
import org.springframework.security.oauth2.client.token.grant.implicit.ImplicitAccessTokenProvider;
import org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordAccessTokenProvider;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client;
import org.springframework.web.client.RestOperations;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@ -45,7 +48,7 @@ public class WebConfig extends WebMvcConfigurerAdapter {
}
@Bean
public RedditController redditController(@Qualifier("redditRestTemplate") RestOperations redditRestTemplate) {
public RedditController redditController(@Qualifier("redditRestTemplate") OAuth2RestTemplate redditRestTemplate) {
RedditController controller = new RedditController();
controller.setRedditRestTemplate(redditRestTemplate);
return controller;
@ -82,12 +85,16 @@ public class WebConfig extends WebMvcConfigurerAdapter {
details.setUserAuthorizationUri(userAuthorizationUri);
details.setTokenName("oauth_token");
details.setScope(Arrays.asList("identity"));
details.setGrantType("authorization_code");
return details;
}
@Bean
public OAuth2RestTemplate redditRestTemplate(OAuth2ClientContext clientContext) {
OAuth2RestTemplate template = new OAuth2RestTemplate(reddit(), clientContext);
AccessTokenProvider accessTokenProvider = new MyAccessTokenProviderChain(Arrays.<AccessTokenProvider> asList(new MyAuthorizationCodeAccessTokenProvider(), new ImplicitAccessTokenProvider(), new ResourceOwnerPasswordAccessTokenProvider(),
new ClientCredentialsAccessTokenProvider()));
template.setAccessTokenProvider(accessTokenProvider);
return template;
}
}

View File

@ -0,0 +1,8 @@
package org.baeldung.persistence.dao;
import org.baeldung.persistence.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {
public User findByUsername(String name);
}

View File

@ -0,0 +1,44 @@
package org.baeldung.persistence.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String username;
private String password;
public User() {
super();
}
public User(String username, String password) {
super();
this.username = username;
this.password = password;
}
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;
}
}

View File

@ -0,0 +1,46 @@
package org.baeldung.security;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import org.baeldung.persistence.dao.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service("userDetailsService")
@Transactional
public class MyUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
public MyUserDetailsService() {
super();
}
@Override
public UserDetails loadUserByUsername(final String name) {
org.baeldung.persistence.model.User user = userRepository.findByUsername(name);
if (user == null) {
user = new org.baeldung.persistence.model.User(name, UUID.randomUUID().toString());
user = userRepository.save(user);
}
return new User(user.getUsername(), user.getPassword(), getGrantedAuthorities(Arrays.asList("ROLE_USER")));
}
private static List<GrantedAuthority> getGrantedAuthorities(List<String> roles) {
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
for (String role : roles) {
authorities.add(new SimpleGrantedAuthority(role));
}
return authorities;
}
}

View File

@ -0,0 +1,47 @@
package org.baeldung.web;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
@Controller
public class RedditController {
@Autowired
private UserDetailsService userDetailsService;
private OAuth2RestTemplate redditRestTemplate;
@RequestMapping("/info")
public String getInfo(Model model) throws Exception {
String result = redditRestTemplate.getForObject("https://oauth.reddit.com/api/v1/me", String.class);
JsonNode node = new ObjectMapper().readTree(result);
String name = node.get("name").asText();
model.addAttribute("info", name);
UserDetails userDetails = userDetailsService.loadUserByUsername(name);
Authentication authentication = new UsernamePasswordAuthenticationToken(userDetails, userDetails.getPassword(), userDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authentication);
return "reddit";
}
@RequestMapping("/reddit/test")
public String test(Model model) {
return "test";
}
public void setRedditRestTemplate(OAuth2RestTemplate redditRestTemplate) {
this.redditRestTemplate = redditRestTemplate;
}
}

View File

@ -0,0 +1,10 @@
################### DataSource Configuration ##########################
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3606/oauth?createDatabaseIfNotExist=true
jdbc.user=tutorialuser
jdbc.pass=tutorialmy5ql
init-db=false
################### Hibernate Configuration ##########################
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.show_sql=false
hibernate.hbm2ddl.auto=create-drop

View File

@ -3,7 +3,7 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Spring OAuth</title>
<title>Spring Security OAuth</title>
</head>
<body>
<h1>Your Reddit Info</h1>

View File

@ -0,0 +1,12 @@
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Spring Security OAuth</title>
</head>
<body>
<h1>Test</h1>
<b>Test </b>
</body>
</html>

View File

@ -4,12 +4,12 @@
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Spring OAuth</title>
<title>Spring Security OAuth</title>
</head>
<body>
<h1>Welcome to Spring OAuth</h1>
<a href="reddit/info">Login with Reddit</a>
<h1>Welcome to Spring Security OAuth</h1>
<a href="info">Login with Reddit</a>
</body>
</html>