diff --git a/.yo-rc.json b/.yo-rc.json
index b144e84bf..be5eb8064 100644
--- a/.yo-rc.json
+++ b/.yo-rc.json
@@ -12,7 +12,6 @@
"prodDatabaseType": "mysql",
"useCompass": false,
"buildTool": "maven",
- "rememberMeKey": "5c37379956bd1242f5636c8cb322c2966ad81277",
"searchEngine": false,
"enableTranslation": true,
"applicationType": "monolith",
@@ -31,6 +30,7 @@
"messageBroker": false,
"serviceDiscoveryType": false,
"clientPackageManager": "yarn",
- "clientFramework": "angular1"
+ "clientFramework": "angular1",
+ "jwtSecretKey": "07a00779cfd8d372c73b40631b62c81503e1b18e"
}
-}
+}
\ No newline at end of file
diff --git a/README.md b/README.md
index e5914f95e..fe2584b8c 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
# jhipsterSampleApplication
-This application was generated using JHipster 4.7.0, you can find documentation and help at [https://jhipster.github.io/documentation-archive/v4.7.0](https://jhipster.github.io/documentation-archive/v4.7.0).
+This application was generated using JHipster 4.7.0, you can find documentation and help at [http://www.jhipster.tech/documentation-archive/v4.7.0](http://www.jhipster.tech/documentation-archive/v4.7.0).
## Development
@@ -32,6 +32,7 @@ Add the `-h` flag on any command to see how you can use it. For example, `bower
For further instructions on how to develop with JHipster, have a look at [Using JHipster in development][].
+
## Building for production
To optimize the jhipsterSampleApplication application for production, run:
@@ -83,7 +84,7 @@ To stop it and remove the container, run:
You can also fully dockerize your application and all the services that it depends on.
To achieve this, first build a docker image of your app by running:
- ./mvnw package -Pprod docker:build
+ ./mvnw package -Pprod dockerfile:build
Then run:
@@ -95,14 +96,14 @@ For more information refer to [Using Docker and Docker-Compose][], this page als
To configure CI for your project, run the ci-cd sub-generator (`jhipster ci-cd`), this will let you generate configuration files for a number of Continuous Integration systems. Consult the [Setting up Continuous Integration][] page for more information.
-[JHipster Homepage and latest documentation]: https://jhipster.github.io
-[JHipster 4.7.0 archive]: https://jhipster.github.io/documentation-archive/v4.7.0
+[JHipster Homepage and latest documentation]: http://www.jhipster.tech
+[JHipster 4.7.0 archive]: http://www.jhipster.tech/documentation-archive/v4.7.0
-[Using JHipster in development]: https://jhipster.github.io/documentation-archive/v4.7.0/development/
-[Using Docker and Docker-Compose]: https://jhipster.github.io/documentation-archive/v4.7.0/docker-compose
-[Using JHipster in production]: https://jhipster.github.io/documentation-archive/v4.7.0/production/
-[Running tests page]: https://jhipster.github.io/documentation-archive/v4.7.0/running-tests/
-[Setting up Continuous Integration]: https://jhipster.github.io/documentation-archive/v4.7.0/setting-up-ci/
+[Using JHipster in development]: http://www.jhipster.tech/documentation-archive/v4.7.0/development/
+[Using Docker and Docker-Compose]: http://www.jhipster.tech/documentation-archive/v4.7.0/docker-compose
+[Using JHipster in production]: http://www.jhipster.tech/documentation-archive/v4.7.0/production/
+[Running tests page]: http://www.jhipster.tech/documentation-archive/v4.7.0/running-tests/
+[Setting up Continuous Integration]: http://www.jhipster.tech/documentation-archive/v4.7.0/setting-up-ci/
[Gatling]: http://gatling.io/
[Node.js]: https://nodejs.org/
diff --git a/gulp/utils.js b/gulp/utils.js
index abb80d3e3..f2379211f 100644
--- a/gulp/utils.js
+++ b/gulp/utils.js
@@ -18,6 +18,9 @@ function parseVersion() {
var version = null;
var pomXml = fs.readFileSync('pom.xml', 'utf8');
parseString(pomXml, function (err, result) {
+ if (err) {
+ throw new Error('Failed to parse pom.xml: ' + err);
+ }
if (result.project.version && result.project.version[0]) {
version = result.project.version[0];
} else if (result.project.parent && result.project.parent[0] && result.project.parent[0].version && result.project.parent[0].version[0]) {
diff --git a/gulpfile.js b/gulpfile.js
index 12fec5d5c..72f6a257f 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -1,4 +1,4 @@
-// Generated on 2017-08-23 using generator-jhipster 4.7.0
+// Generated on 2017-09-08 using generator-jhipster 4.7.0
'use strict';
var gulp = require('gulp'),
diff --git a/pom.xml b/pom.xml
index 113159fb2..b3657245d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,19 +21,20 @@
2.0.02.53.5
- 0.4.13
+ 1.3.43.2.21.42.2.52.2.4
- 5.2.8.Final
+ 5.2.10.Final2.6.00.7.91.81.0.01.1.31.1.9
+ 0.7.03.62.0.04.11
@@ -342,6 +343,11 @@
+
+ io.jsonwebtoken
+ jjwt
+ ${jjwt.version}
+ net.logstash.logback
@@ -480,6 +486,25 @@
+
+ docker-resources
+ validate
+
+ copy-resources
+
+
+ target/
+
+
+ src/main/docker/
+ true
+
+ **/*.yml
+
+
+
+
+
@@ -577,18 +602,24 @@
com.spotify
- docker-maven-plugin
- ${docker-maven-plugin.version}
+ dockerfile-maven-plugin
+ ${dockerfile-maven-plugin.version}
+
- jhipstersampleapplication
- src/main/docker
-
-
- /
- ${project.build.directory}
- ${project.build.finalName}.war
-
-
+ ${project.artifactId}
+ latest
+ ${project.build.directory}
@@ -683,6 +714,14 @@
maven-war-pluginsrc/main/webapp/
+
+
+ src/main/webapp
+
+ WEB-INF/**
+
+
+
@@ -719,6 +758,14 @@
maven-war-plugintarget/www/
+
+
+ src/main/webapp
+
+ WEB-INF/**
+
+
+
diff --git a/src/main/docker/.dockerignore b/src/main/docker/.dockerignore
new file mode 100644
index 000000000..28e6b1387
--- /dev/null
+++ b/src/main/docker/.dockerignore
@@ -0,0 +1,5 @@
+# https://docs.docker.com/engine/reference/builder/#dockerignore-file
+# by default ignore everything except the jar file
+**/*
+!*.jar
+!*.war
diff --git a/src/main/docker/Dockerfile b/src/main/docker/Dockerfile
index 2dcafb4dc..6fae8c834 100644
--- a/src/main/docker/Dockerfile
+++ b/src/main/docker/Dockerfile
@@ -4,8 +4,7 @@ ENV SPRING_OUTPUT_ANSI_ENABLED=ALWAYS \
JHIPSTER_SLEEP=0 \
JAVA_OPTS=""
-# add directly the war
-ADD *.war /app.war
+ADD @project.build.finalName@.war /app.war
EXPOSE 8080
CMD echo "The application will start in ${JHIPSTER_SLEEP}s..." && \
diff --git a/src/main/java/io/github/jhipster/sample/JhipsterSampleApplicationApp.java b/src/main/java/io/github/jhipster/sample/JhipsterSampleApplicationApp.java
index 0fc41a52a..0d866a092 100644
--- a/src/main/java/io/github/jhipster/sample/JhipsterSampleApplicationApp.java
+++ b/src/main/java/io/github/jhipster/sample/JhipsterSampleApplicationApp.java
@@ -39,7 +39,7 @@ public JhipsterSampleApplicationApp(Environment env) {
*
* Spring profiles can be configured with a program arguments --spring.profiles.active=your-active-profile
*
- * Persistent tokens are used by Spring Security to automatically log in users.
- *
- * This is a specific implementation of Spring Security's remember-me authentication, but it is much
- * more powerful than the standard implementations:
- *
- *
It allows a user to see the list of his currently opened sessions, and invalidate them
- *
It stores more information, such as the IP address and the user agent, for audit purposes
- *
When a user logs out, only his current session is invalidated, and not all of his sessions
- *
- *
- * Please note that it allows the use of the same token for 5 seconds, and this value stored in a specific
- * cache during that period. This is to allow concurrent requests from the same user: otherwise, two
- * requests being sent at the same time could invalidate each other's token.
- *
- * The main algorithm comes from Spring Security's PersistentTokenBasedRememberMeServices, but this class
- * couldn't be cleanly extended.
- */
-@Service
-public class PersistentTokenRememberMeServices extends
- AbstractRememberMeServices {
-
- private final Logger log = LoggerFactory.getLogger(PersistentTokenRememberMeServices.class);
-
- // Token is valid for one month
- private static final int TOKEN_VALIDITY_DAYS = 31;
-
- private static final int TOKEN_VALIDITY_SECONDS = 60 * 60 * 24 * TOKEN_VALIDITY_DAYS;
-
- private static final int UPGRADED_TOKEN_VALIDITY_SECONDS = 5;
-
- private Cache upgradedTokenCache = CacheBuilder.newBuilder()
- .expireAfterWrite(UPGRADED_TOKEN_VALIDITY_SECONDS, TimeUnit.SECONDS)
- .build();
-
- private final PersistentTokenRepository persistentTokenRepository;
-
- private final UserRepository userRepository;
-
- public PersistentTokenRememberMeServices(JHipsterProperties jHipsterProperties,
- org.springframework.security.core.userdetails.UserDetailsService userDetailsService,
- PersistentTokenRepository persistentTokenRepository, UserRepository userRepository) {
-
- super(jHipsterProperties.getSecurity().getRememberMe().getKey(), userDetailsService);
- this.persistentTokenRepository = persistentTokenRepository;
- this.userRepository = userRepository;
- }
-
- @Override
- protected UserDetails processAutoLoginCookie(String[] cookieTokens, HttpServletRequest request,
- HttpServletResponse response) {
-
- synchronized (this) { // prevent 2 authentication requests from the same user in parallel
- String login = null;
- UpgradedRememberMeToken upgradedToken = upgradedTokenCache.getIfPresent(cookieTokens[0]);
- if (upgradedToken != null) {
- login = upgradedToken.getUserLoginIfValidAndRecentUpgrade(cookieTokens);
- log.debug("Detected previously upgraded login token for user '{}'", login);
- }
-
- if (login == null) {
- PersistentToken token = getPersistentToken(cookieTokens);
- login = token.getUser().getLogin();
-
- // Token also matches, so login is valid. Update the token value, keeping the *same* series number.
- log.debug("Refreshing persistent login token for user '{}', series '{}'", login, token.getSeries());
- token.setTokenDate(LocalDate.now());
- token.setTokenValue(RandomUtil.generateTokenData());
- token.setIpAddress(request.getRemoteAddr());
- token.setUserAgent(request.getHeader("User-Agent"));
- try {
- persistentTokenRepository.saveAndFlush(token);
- } catch (DataAccessException e) {
- log.error("Failed to update token: ", e);
- throw new RememberMeAuthenticationException("Autologin failed due to data access problem", e);
- }
- addCookie(token, request, response);
- upgradedTokenCache.put(cookieTokens[0], new UpgradedRememberMeToken(cookieTokens, login));
- }
- return getUserDetailsService().loadUserByUsername(login);
- }
- }
-
- @Override
- protected void onLoginSuccess(HttpServletRequest request, HttpServletResponse response, Authentication
- successfulAuthentication) {
-
- String login = successfulAuthentication.getName();
-
- log.debug("Creating new persistent login for user {}", login);
- PersistentToken token = userRepository.findOneByLogin(login).map(u -> {
- PersistentToken t = new PersistentToken();
- t.setSeries(RandomUtil.generateSeriesData());
- t.setUser(u);
- t.setTokenValue(RandomUtil.generateTokenData());
- t.setTokenDate(LocalDate.now());
- t.setIpAddress(request.getRemoteAddr());
- t.setUserAgent(request.getHeader("User-Agent"));
- return t;
- }).orElseThrow(() -> new UsernameNotFoundException("User " + login + " was not found in the database"));
- try {
- persistentTokenRepository.saveAndFlush(token);
- addCookie(token, request, response);
- } catch (DataAccessException e) {
- log.error("Failed to save persistent token ", e);
- }
- }
-
- /**
- * When logout occurs, only invalidate the current token, and not all user sessions.
- *
- * The standard Spring Security implementations are too basic: they invalidate all tokens for the
- * current user, so when he logs out from one browser, all his other sessions are destroyed.
- */
- @Override
- @Transactional
- public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
- String rememberMeCookie = extractRememberMeCookie(request);
- if (rememberMeCookie != null && rememberMeCookie.length() != 0) {
- try {
- String[] cookieTokens = decodeCookie(rememberMeCookie);
- PersistentToken token = getPersistentToken(cookieTokens);
- persistentTokenRepository.delete(token);
- } catch (InvalidCookieException ice) {
- log.info("Invalid cookie, no persistent token could be deleted", ice);
- } catch (RememberMeAuthenticationException rmae) {
- log.debug("No persistent token found, so no token could be deleted", rmae);
- }
- }
- super.logout(request, response, authentication);
- }
-
- /**
- * Validate the token and return it.
- */
- private PersistentToken getPersistentToken(String[] cookieTokens) {
- if (cookieTokens.length != 2) {
- throw new InvalidCookieException("Cookie token did not contain " + 2 +
- " tokens, but contained '" + Arrays.asList(cookieTokens) + "'");
- }
- String presentedSeries = cookieTokens[0];
- String presentedToken = cookieTokens[1];
- PersistentToken token = persistentTokenRepository.findOne(presentedSeries);
-
- if (token == null) {
- // No series match, so we can't authenticate using this cookie
- throw new RememberMeAuthenticationException("No persistent token found for series id: " + presentedSeries);
- }
-
- // We have a match for this user/series combination
- log.info("presentedToken={} / tokenValue={}", presentedToken, token.getTokenValue());
- if (!presentedToken.equals(token.getTokenValue())) {
- // Token doesn't match series value. Delete this session and throw an exception.
- persistentTokenRepository.delete(token);
- throw new CookieTheftException("Invalid remember-me token (Series/token) mismatch. Implies previous " +
- "cookie theft attack.");
- }
-
- if (token.getTokenDate().plusDays(TOKEN_VALIDITY_DAYS).isBefore(LocalDate.now())) {
- persistentTokenRepository.delete(token);
- throw new RememberMeAuthenticationException("Remember-me login has expired");
- }
- return token;
- }
-
- private void addCookie(PersistentToken token, HttpServletRequest request, HttpServletResponse response) {
- setCookie(
- new String[]{token.getSeries(), token.getTokenValue()},
- TOKEN_VALIDITY_SECONDS, request, response);
- }
-
- private static class UpgradedRememberMeToken implements Serializable {
-
- private static final long serialVersionUID = 1L;
-
- private String[] upgradedToken;
-
- private Date upgradeTime;
-
- private String userLogin;
-
- UpgradedRememberMeToken(String[] upgradedToken, String userLogin) {
- this.upgradedToken = upgradedToken;
- this.userLogin = userLogin;
- this.upgradeTime = new Date();
- }
-
- String getUserLoginIfValidAndRecentUpgrade(String[] currentToken) {
- if (currentToken[0].equals(this.upgradedToken[0]) &&
- currentToken[1].equals(this.upgradedToken[1]) &&
- (upgradeTime.getTime() + UPGRADED_TOKEN_VALIDITY_SECONDS * 1000) > new Date().getTime()) {
- return this.userLogin;
- }
- return null;
- }
- }
-}
diff --git a/src/main/java/io/github/jhipster/sample/security/SecurityUtils.java b/src/main/java/io/github/jhipster/sample/security/SecurityUtils.java
index 03756ff76..e6ed57bc2 100644
--- a/src/main/java/io/github/jhipster/sample/security/SecurityUtils.java
+++ b/src/main/java/io/github/jhipster/sample/security/SecurityUtils.java
@@ -33,6 +33,20 @@ public static String getCurrentUserLogin() {
return userName;
}
+ /**
+ * Get the JWT of the current user.
+ *
+ * @return the JWT of the current user
+ */
+ public static String getCurrentUserJWT() {
+ SecurityContext securityContext = SecurityContextHolder.getContext();
+ Authentication authentication = securityContext.getAuthentication();
+ if (authentication != null && authentication.getCredentials() instanceof String) {
+ return (String) authentication.getCredentials();
+ }
+ return null;
+ }
+
/**
* Check if a user is authenticated.
*
diff --git a/src/main/java/io/github/jhipster/sample/security/jwt/JWTConfigurer.java b/src/main/java/io/github/jhipster/sample/security/jwt/JWTConfigurer.java
new file mode 100644
index 000000000..88da16d60
--- /dev/null
+++ b/src/main/java/io/github/jhipster/sample/security/jwt/JWTConfigurer.java
@@ -0,0 +1,23 @@
+package io.github.jhipster.sample.security.jwt;
+
+import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.web.DefaultSecurityFilterChain;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+
+public class JWTConfigurer extends SecurityConfigurerAdapter {
+
+ public static final String AUTHORIZATION_HEADER = "Authorization";
+
+ private TokenProvider tokenProvider;
+
+ public JWTConfigurer(TokenProvider tokenProvider) {
+ this.tokenProvider = tokenProvider;
+ }
+
+ @Override
+ public void configure(HttpSecurity http) throws Exception {
+ JWTFilter customFilter = new JWTFilter(tokenProvider);
+ http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class);
+ }
+}
diff --git a/src/main/java/io/github/jhipster/sample/security/jwt/JWTFilter.java b/src/main/java/io/github/jhipster/sample/security/jwt/JWTFilter.java
new file mode 100644
index 000000000..6daa2c4c4
--- /dev/null
+++ b/src/main/java/io/github/jhipster/sample/security/jwt/JWTFilter.java
@@ -0,0 +1,46 @@
+package io.github.jhipster.sample.security.jwt;
+
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.util.StringUtils;
+import org.springframework.web.filter.GenericFilterBean;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+
+/**
+ * Filters incoming requests and installs a Spring Security principal if a header corresponding to a valid user is
+ * found.
+ */
+public class JWTFilter extends GenericFilterBean {
+
+ private TokenProvider tokenProvider;
+
+ public JWTFilter(TokenProvider tokenProvider) {
+ this.tokenProvider = tokenProvider;
+ }
+
+ @Override
+ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
+ throws IOException, ServletException {
+ HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
+ String jwt = resolveToken(httpServletRequest);
+ if (StringUtils.hasText(jwt) && this.tokenProvider.validateToken(jwt)) {
+ Authentication authentication = this.tokenProvider.getAuthentication(jwt);
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+ }
+ filterChain.doFilter(servletRequest, servletResponse);
+ }
+
+ private String resolveToken(HttpServletRequest request){
+ String bearerToken = request.getHeader(JWTConfigurer.AUTHORIZATION_HEADER);
+ if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
+ return bearerToken.substring(7, bearerToken.length());
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/io/github/jhipster/sample/security/jwt/TokenProvider.java b/src/main/java/io/github/jhipster/sample/security/jwt/TokenProvider.java
new file mode 100644
index 000000000..5adb611a1
--- /dev/null
+++ b/src/main/java/io/github/jhipster/sample/security/jwt/TokenProvider.java
@@ -0,0 +1,109 @@
+package io.github.jhipster.sample.security.jwt;
+
+import io.github.jhipster.config.JHipsterProperties;
+
+import java.util.*;
+import java.util.stream.Collectors;
+import javax.annotation.PostConstruct;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.stereotype.Component;
+
+import io.jsonwebtoken.*;
+
+@Component
+public class TokenProvider {
+
+ private final Logger log = LoggerFactory.getLogger(TokenProvider.class);
+
+ private static final String AUTHORITIES_KEY = "auth";
+
+ private String secretKey;
+
+ private long tokenValidityInMilliseconds;
+
+ private long tokenValidityInMillisecondsForRememberMe;
+
+ private final JHipsterProperties jHipsterProperties;
+
+ public TokenProvider(JHipsterProperties jHipsterProperties) {
+ this.jHipsterProperties = jHipsterProperties;
+ }
+
+ @PostConstruct
+ public void init() {
+ this.secretKey =
+ jHipsterProperties.getSecurity().getAuthentication().getJwt().getSecret();
+
+ this.tokenValidityInMilliseconds =
+ 1000 * jHipsterProperties.getSecurity().getAuthentication().getJwt().getTokenValidityInSeconds();
+ this.tokenValidityInMillisecondsForRememberMe =
+ 1000 * jHipsterProperties.getSecurity().getAuthentication().getJwt().getTokenValidityInSecondsForRememberMe();
+ }
+
+ public String createToken(Authentication authentication, Boolean rememberMe) {
+ String authorities = authentication.getAuthorities().stream()
+ .map(GrantedAuthority::getAuthority)
+ .collect(Collectors.joining(","));
+
+ long now = (new Date()).getTime();
+ Date validity;
+ if (rememberMe) {
+ validity = new Date(now + this.tokenValidityInMillisecondsForRememberMe);
+ } else {
+ validity = new Date(now + this.tokenValidityInMilliseconds);
+ }
+
+ return Jwts.builder()
+ .setSubject(authentication.getName())
+ .claim(AUTHORITIES_KEY, authorities)
+ .signWith(SignatureAlgorithm.HS512, secretKey)
+ .setExpiration(validity)
+ .compact();
+ }
+
+ public Authentication getAuthentication(String token) {
+ Claims claims = Jwts.parser()
+ .setSigningKey(secretKey)
+ .parseClaimsJws(token)
+ .getBody();
+
+ Collection extends GrantedAuthority> authorities =
+ Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(","))
+ .map(SimpleGrantedAuthority::new)
+ .collect(Collectors.toList());
+
+ User principal = new User(claims.getSubject(), "", authorities);
+
+ return new UsernamePasswordAuthenticationToken(principal, token, authorities);
+ }
+
+ public boolean validateToken(String authToken) {
+ try {
+ Jwts.parser().setSigningKey(secretKey).parseClaimsJws(authToken);
+ return true;
+ } catch (SignatureException e) {
+ log.info("Invalid JWT signature.");
+ log.trace("Invalid JWT signature trace: {}", e);
+ } catch (MalformedJwtException e) {
+ log.info("Invalid JWT token.");
+ log.trace("Invalid JWT token trace: {}", e);
+ } catch (ExpiredJwtException e) {
+ log.info("Expired JWT token.");
+ log.trace("Expired JWT token trace: {}", e);
+ } catch (UnsupportedJwtException e) {
+ log.info("Unsupported JWT token.");
+ log.trace("Unsupported JWT token trace: {}", e);
+ } catch (IllegalArgumentException e) {
+ log.info("JWT token compact of handler are invalid.");
+ log.trace("JWT token compact of handler are invalid trace: {}", e);
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/io/github/jhipster/sample/service/UserService.java b/src/main/java/io/github/jhipster/sample/service/UserService.java
index 7cd824aaf..d24af9518 100644
--- a/src/main/java/io/github/jhipster/sample/service/UserService.java
+++ b/src/main/java/io/github/jhipster/sample/service/UserService.java
@@ -3,7 +3,6 @@
import io.github.jhipster.sample.domain.Authority;
import io.github.jhipster.sample.domain.User;
import io.github.jhipster.sample.repository.AuthorityRepository;
-import io.github.jhipster.sample.repository.PersistentTokenRepository;
import io.github.jhipster.sample.config.Constants;
import io.github.jhipster.sample.repository.UserRepository;
import io.github.jhipster.sample.security.AuthoritiesConstants;
@@ -13,6 +12,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.cache.CacheManager;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.scheduling.annotation.Scheduled;
@@ -20,7 +20,6 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
-import java.time.LocalDate;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.*;
@@ -39,15 +38,15 @@ public class UserService {
private final PasswordEncoder passwordEncoder;
- private final PersistentTokenRepository persistentTokenRepository;
-
private final AuthorityRepository authorityRepository;
- public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder, PersistentTokenRepository persistentTokenRepository, AuthorityRepository authorityRepository) {
+ private final CacheManager cacheManager;
+
+ public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder, AuthorityRepository authorityRepository, CacheManager cacheManager) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
- this.persistentTokenRepository = persistentTokenRepository;
this.authorityRepository = authorityRepository;
+ this.cacheManager = cacheManager;
}
public Optional activateRegistration(String key) {
@@ -57,6 +56,7 @@ public Optional activateRegistration(String key) {
// activate given user for the registration key.
user.setActivated(true);
user.setActivationKey(null);
+ cacheManager.getCache("users").evict(user.getLogin());
log.debug("Activated user: {}", user);
return user;
});
@@ -71,6 +71,7 @@ public Optional completePasswordReset(String newPassword, String key) {
user.setPassword(passwordEncoder.encode(newPassword));
user.setResetKey(null);
user.setResetDate(null);
+ cacheManager.getCache("users").evict(user.getLogin());
return user;
});
}
@@ -81,6 +82,7 @@ public Optional requestPasswordReset(String mail) {
.map(user -> {
user.setResetKey(RandomUtil.generateResetKey());
user.setResetDate(Instant.now());
+ cacheManager.getCache("users").evict(user.getLogin());
return user;
});
}
@@ -156,6 +158,7 @@ public void updateUser(String firstName, String lastName, String email, String l
user.setEmail(email);
user.setLangKey(langKey);
user.setImageUrl(imageUrl);
+ cacheManager.getCache("users").evict(user.getLogin());
log.debug("Changed Information for User: {}", user);
});
}
@@ -182,6 +185,7 @@ public Optional updateUser(UserDTO userDTO) {
userDTO.getAuthorities().stream()
.map(authorityRepository::findOne)
.forEach(managedAuthorities::add);
+ cacheManager.getCache("users").evict(user.getLogin());
log.debug("Changed Information for User: {}", user);
return user;
})
@@ -191,6 +195,7 @@ public Optional updateUser(UserDTO userDTO) {
public void deleteUser(String login) {
userRepository.findOneByLogin(login).ifPresent(user -> {
userRepository.delete(user);
+ cacheManager.getCache("users").evict(login);
log.debug("Deleted User: {}", user);
});
}
@@ -199,6 +204,7 @@ public void changePassword(String password) {
userRepository.findOneByLogin(SecurityUtils.getCurrentUserLogin()).ifPresent(user -> {
String encryptedPassword = passwordEncoder.encode(password);
user.setPassword(encryptedPassword);
+ cacheManager.getCache("users").evict(user.getLogin());
log.debug("Changed password for User: {}", user);
});
}
@@ -223,23 +229,6 @@ public User getUserWithAuthorities() {
return userRepository.findOneWithAuthoritiesByLogin(SecurityUtils.getCurrentUserLogin()).orElse(null);
}
- /**
- * Persistent Token are used for providing automatic authentication, they should be automatically deleted after
- * 30 days.
- *
- * This is scheduled to get fired everyday, at midnight.
- */
- @Scheduled(cron = "0 0 0 * * ?")
- public void removeOldPersistentTokens() {
- LocalDate now = LocalDate.now();
- persistentTokenRepository.findByTokenDateBefore(now.minusMonths(1)).forEach(token -> {
- log.debug("Deleting token {}", token.getSeries());
- User user = token.getUser();
- user.getPersistentTokens().remove(token);
- persistentTokenRepository.delete(token);
- });
- }
-
/**
* Not activated users should be automatically deleted after 3 days.
*
@@ -251,6 +240,7 @@ public void removeNotActivatedUsers() {
for (User user : users) {
log.debug("Deleting not activated user {}", user.getLogin());
userRepository.delete(user);
+ cacheManager.getCache("users").evict(user.getLogin());
}
}
diff --git a/src/main/java/io/github/jhipster/sample/service/util/RandomUtil.java b/src/main/java/io/github/jhipster/sample/service/util/RandomUtil.java
index 7ecb4e2dc..468232b53 100644
--- a/src/main/java/io/github/jhipster/sample/service/util/RandomUtil.java
+++ b/src/main/java/io/github/jhipster/sample/service/util/RandomUtil.java
@@ -38,23 +38,4 @@ public static String generateActivationKey() {
public static String generateResetKey() {
return RandomStringUtils.randomNumeric(DEF_COUNT);
}
-
- /**
- * Generate a unique series to validate a persistent token, used in the
- * authentication remember-me mechanism.
- *
- * @return the generated series data
- */
- public static String generateSeriesData() {
- return RandomStringUtils.randomAlphanumeric(DEF_COUNT);
- }
-
- /**
- * Generate a persistent token, used in the authentication remember-me mechanism.
- *
- * @return the generated token data
- */
- public static String generateTokenData() {
- return RandomStringUtils.randomAlphanumeric(DEF_COUNT);
- }
}
diff --git a/src/main/java/io/github/jhipster/sample/web/rest/AccountResource.java b/src/main/java/io/github/jhipster/sample/web/rest/AccountResource.java
index 9f5005d62..f3041717f 100644
--- a/src/main/java/io/github/jhipster/sample/web/rest/AccountResource.java
+++ b/src/main/java/io/github/jhipster/sample/web/rest/AccountResource.java
@@ -2,9 +2,7 @@
import com.codahale.metrics.annotation.Timed;
-import io.github.jhipster.sample.domain.PersistentToken;
import io.github.jhipster.sample.domain.User;
-import io.github.jhipster.sample.repository.PersistentTokenRepository;
import io.github.jhipster.sample.repository.UserRepository;
import io.github.jhipster.sample.security.SecurityUtils;
import io.github.jhipster.sample.service.MailService;
@@ -25,8 +23,6 @@
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
-import java.io.UnsupportedEncodingException;
-import java.net.URLDecoder;
import java.util.*;
/**
@@ -44,17 +40,14 @@ public class AccountResource {
private final MailService mailService;
- private final PersistentTokenRepository persistentTokenRepository;
-
private static final String CHECK_ERROR_MESSAGE = "Incorrect password";
public AccountResource(UserRepository userRepository, UserService userService,
- MailService mailService, PersistentTokenRepository persistentTokenRepository) {
+ MailService mailService) {
this.userRepository = userRepository;
this.userService = userService;
this.mailService = mailService;
- this.persistentTokenRepository = persistentTokenRepository;
}
/**
@@ -155,12 +148,12 @@ public ResponseEntity saveAccount(@Valid @RequestBody UserDTO userDTO) {
}
/**
- * POST /account/change_password : changes the current user's password
+ * POST /account/change-password : changes the current user's password
*
* @param password the new password
* @return the ResponseEntity with status 200 (OK), or status 400 (Bad Request) if the new password is not strong enough
*/
- @PostMapping(path = "/account/change_password",
+ @PostMapping(path = "/account/change-password",
produces = MediaType.TEXT_PLAIN_VALUE)
@Timed
public ResponseEntity changePassword(@RequestBody String password) {
@@ -172,54 +165,12 @@ public ResponseEntity changePassword(@RequestBody String password) {
}
/**
- * GET /account/sessions : get the current open sessions.
- *
- * @return the ResponseEntity with status 200 (OK) and the current open sessions in body,
- * or status 500 (Internal Server Error) if the current open sessions couldn't be retrieved
- */
- @GetMapping("/account/sessions")
- @Timed
- public ResponseEntity> getCurrentSessions() {
- return userRepository.findOneByLogin(SecurityUtils.getCurrentUserLogin())
- .map(user -> new ResponseEntity<>(
- persistentTokenRepository.findByUser(user),
- HttpStatus.OK))
- .orElse(new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR));
- }
-
- /**
- * DELETE /account/sessions?series={series} : invalidate an existing session.
- *
- * - You can only delete your own sessions, not any other user's session
- * - If you delete one of your existing sessions, and that you are currently logged in on that session, you will
- * still be able to use that session, until you quit your browser: it does not work in real time (there is
- * no API for that), it only removes the "remember me" cookie
- * - This is also true if you invalidate your current session: you will still be able to use it until you close
- * your browser or that the session times out. But automatic login (the "remember me" cookie) will not work
- * anymore.
- * There is an API to invalidate the current session, but there is no API to check which session uses which
- * cookie.
- *
- * @param series the series of an existing session
- * @throws UnsupportedEncodingException if the series couldnt be URL decoded
- */
- @DeleteMapping("/account/sessions/{series}")
- @Timed
- public void invalidateSession(@PathVariable String series) throws UnsupportedEncodingException {
- String decodedSeries = URLDecoder.decode(series, "UTF-8");
- userRepository.findOneByLogin(SecurityUtils.getCurrentUserLogin()).ifPresent(u ->
- persistentTokenRepository.findByUser(u).stream()
- .filter(persistentToken -> StringUtils.equals(persistentToken.getSeries(), decodedSeries))
- .findAny().ifPresent(t -> persistentTokenRepository.delete(decodedSeries)));
- }
-
- /**
- * POST /account/reset_password/init : Send an email to reset the password of the user
+ * POST /account/reset-password/init : Send an email to reset the password of the user
*
* @param mail the mail of the user
* @return the ResponseEntity with status 200 (OK) if the email was sent, or status 400 (Bad Request) if the email address is not registered
*/
- @PostMapping(path = "/account/reset_password/init",
+ @PostMapping(path = "/account/reset-password/init",
produces = MediaType.TEXT_PLAIN_VALUE)
@Timed
public ResponseEntity requestPasswordReset(@RequestBody String mail) {
@@ -231,13 +182,13 @@ public ResponseEntity requestPasswordReset(@RequestBody String mail) {
}
/**
- * POST /account/reset_password/finish : Finish to reset the password of the user
+ * POST /account/reset-password/finish : Finish to reset the password of the user
*
* @param keyAndPassword the generated key and the new password
* @return the ResponseEntity with status 200 (OK) if the password has been reset,
* or status 400 (Bad Request) or 500 (Internal Server Error) if the password could not be reset
*/
- @PostMapping(path = "/account/reset_password/finish",
+ @PostMapping(path = "/account/reset-password/finish",
produces = MediaType.TEXT_PLAIN_VALUE)
@Timed
public ResponseEntity finishPasswordReset(@RequestBody KeyAndPasswordVM keyAndPassword) {
diff --git a/src/main/java/io/github/jhipster/sample/web/rest/UserJWTController.java b/src/main/java/io/github/jhipster/sample/web/rest/UserJWTController.java
new file mode 100644
index 000000000..ce1194b8c
--- /dev/null
+++ b/src/main/java/io/github/jhipster/sample/web/rest/UserJWTController.java
@@ -0,0 +1,84 @@
+package io.github.jhipster.sample.web.rest;
+
+import io.github.jhipster.sample.security.jwt.JWTConfigurer;
+import io.github.jhipster.sample.security.jwt.TokenProvider;
+import io.github.jhipster.sample.web.rest.vm.LoginVM;
+
+import com.codahale.metrics.annotation.Timed;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+import java.util.Collections;
+
+/**
+ * Controller to authenticate users.
+ */
+@RestController
+@RequestMapping("/api")
+public class UserJWTController {
+
+ private final Logger log = LoggerFactory.getLogger(UserJWTController.class);
+
+ private final TokenProvider tokenProvider;
+
+ private final AuthenticationManager authenticationManager;
+
+ public UserJWTController(TokenProvider tokenProvider, AuthenticationManager authenticationManager) {
+ this.tokenProvider = tokenProvider;
+ this.authenticationManager = authenticationManager;
+ }
+
+ @PostMapping("/authenticate")
+ @Timed
+ public ResponseEntity authorize(@Valid @RequestBody LoginVM loginVM, HttpServletResponse response) {
+
+ UsernamePasswordAuthenticationToken authenticationToken =
+ new UsernamePasswordAuthenticationToken(loginVM.getUsername(), loginVM.getPassword());
+
+ try {
+ Authentication authentication = this.authenticationManager.authenticate(authenticationToken);
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+ boolean rememberMe = (loginVM.isRememberMe() == null) ? false : loginVM.isRememberMe();
+ String jwt = tokenProvider.createToken(authentication, rememberMe);
+ response.addHeader(JWTConfigurer.AUTHORIZATION_HEADER, "Bearer " + jwt);
+ return ResponseEntity.ok(new JWTToken(jwt));
+ } catch (AuthenticationException ae) {
+ log.trace("Authentication exception trace: {}", ae);
+ return new ResponseEntity<>(Collections.singletonMap("AuthenticationException",
+ ae.getLocalizedMessage()), HttpStatus.UNAUTHORIZED);
+ }
+ }
+
+ /**
+ * Object to return as body in JWT Authentication.
+ */
+ static class JWTToken {
+
+ private String idToken;
+
+ JWTToken(String idToken) {
+ this.idToken = idToken;
+ }
+
+ @JsonProperty("id_token")
+ String getIdToken() {
+ return idToken;
+ }
+
+ void setIdToken(String idToken) {
+ this.idToken = idToken;
+ }
+ }
+}
diff --git a/src/main/java/io/github/jhipster/sample/web/rest/errors/ErrorConstants.java b/src/main/java/io/github/jhipster/sample/web/rest/errors/ErrorConstants.java
index 781231dd2..4efc45a69 100644
--- a/src/main/java/io/github/jhipster/sample/web/rest/errors/ErrorConstants.java
+++ b/src/main/java/io/github/jhipster/sample/web/rest/errors/ErrorConstants.java
@@ -3,7 +3,6 @@
public final class ErrorConstants {
public static final String ERR_CONCURRENCY_FAILURE = "error.concurrencyFailure";
- public static final String ERR_ACCESS_DENIED = "error.accessDenied";
public static final String ERR_VALIDATION = "error.validation";
public static final String ERR_METHOD_NOT_SUPPORTED = "error.methodNotSupported";
public static final String ERR_INTERNAL_SERVER_ERROR = "error.internalServerError";
diff --git a/src/main/java/io/github/jhipster/sample/web/rest/errors/ExceptionTranslator.java b/src/main/java/io/github/jhipster/sample/web/rest/errors/ExceptionTranslator.java
index 68cddc00a..2cf54e5e7 100644
--- a/src/main/java/io/github/jhipster/sample/web/rest/errors/ExceptionTranslator.java
+++ b/src/main/java/io/github/jhipster/sample/web/rest/errors/ExceptionTranslator.java
@@ -14,7 +14,9 @@
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.support.MissingServletRequestPartException;
/**
* Controller advice to translate the server side exceptions to client-friendly json structures.
@@ -51,11 +53,25 @@ public ParameterizedErrorVM processParameterizedValidationError(CustomParameteri
return ex.getErrorVM();
}
+ @ExceptionHandler(MissingServletRequestPartException.class)
+ @ResponseBody
+ @ResponseStatus(HttpStatus.BAD_REQUEST)
+ public ErrorVM processMissingServletRequestPartException(MissingServletRequestPartException e) {
+ return new ErrorVM("error.http." + HttpStatus.BAD_REQUEST, e.getMessage());
+ }
+
+ @ExceptionHandler(MissingServletRequestParameterException.class)
+ @ResponseBody
+ @ResponseStatus(HttpStatus.BAD_REQUEST)
+ public ErrorVM processMissingServletRequestParameterException(MissingServletRequestParameterException e) {
+ return new ErrorVM("error.http." + HttpStatus.BAD_REQUEST, e.getMessage());
+ }
+
@ExceptionHandler(AccessDeniedException.class)
@ResponseStatus(HttpStatus.FORBIDDEN)
@ResponseBody
public ErrorVM processAccessDeniedException(AccessDeniedException e) {
- return new ErrorVM(ErrorConstants.ERR_ACCESS_DENIED, e.getMessage());
+ return new ErrorVM("error.http." + HttpStatus.FORBIDDEN, e.getMessage());
}
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
@@ -77,7 +93,7 @@ public ResponseEntity processException(Exception ex) {
ResponseStatus responseStatus = AnnotationUtils.findAnnotation(ex.getClass(), ResponseStatus.class);
if (responseStatus != null) {
builder = ResponseEntity.status(responseStatus.value());
- errorVM = new ErrorVM("error." + responseStatus.value().value(), responseStatus.reason());
+ errorVM = new ErrorVM("error.http." + responseStatus.value().value(), responseStatus.reason());
} else {
builder = ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR);
errorVM = new ErrorVM(ErrorConstants.ERR_INTERNAL_SERVER_ERROR, "Internal server error");
diff --git a/src/main/java/io/github/jhipster/sample/web/rest/vm/LoginVM.java b/src/main/java/io/github/jhipster/sample/web/rest/vm/LoginVM.java
new file mode 100644
index 000000000..c4bc96501
--- /dev/null
+++ b/src/main/java/io/github/jhipster/sample/web/rest/vm/LoginVM.java
@@ -0,0 +1,55 @@
+package io.github.jhipster.sample.web.rest.vm;
+
+import io.github.jhipster.sample.config.Constants;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+import javax.validation.constraints.Size;
+
+/**
+ * View Model object for storing a user's credentials.
+ */
+public class LoginVM {
+
+ @Pattern(regexp = Constants.LOGIN_REGEX)
+ @NotNull
+ @Size(min = 1, max = 50)
+ private String username;
+
+ @NotNull
+ @Size(min = ManagedUserVM.PASSWORD_MIN_LENGTH, max = ManagedUserVM.PASSWORD_MAX_LENGTH)
+ private String password;
+
+ private Boolean rememberMe;
+
+ 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 Boolean isRememberMe() {
+ return rememberMe;
+ }
+
+ public void setRememberMe(Boolean rememberMe) {
+ this.rememberMe = rememberMe;
+ }
+
+ @Override
+ public String toString() {
+ return "LoginVM{" +
+ "username='" + username + '\'' +
+ ", rememberMe=" + rememberMe +
+ '}';
+ }
+}
diff --git a/src/main/resources/banner.txt b/src/main/resources/banner.txt
index 669a09e24..db090f7e7 100644
--- a/src/main/resources/banner.txt
+++ b/src/main/resources/banner.txt
@@ -7,4 +7,4 @@
${AnsiColor.GREEN} ╚═════╝ ${AnsiColor.RED} ╚═╝ ╚═╝ ╚═══════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══════╝ ╚═╝ ╚═╝
${AnsiColor.BRIGHT_BLUE}:: JHipster 🤓 :: Running Spring Boot ${spring-boot.version} ::
-:: https://jhipster.github.io ::${AnsiColor.DEFAULT}
+:: http://www.jhipster.tech ::${AnsiColor.DEFAULT}
diff --git a/src/main/resources/config/application-dev.yml b/src/main/resources/config/application-dev.yml
index a031be0fe..26a3c184b 100644
--- a/src/main/resources/config/application-dev.yml
+++ b/src/main/resources/config/application-dev.yml
@@ -3,8 +3,8 @@
#
# This configuration overrides the application.yml file.
#
-# More information on profiles: https://jhipster.github.io/profiles/
-# More information on configuration properties: https://jhipster.github.io/common-application-properties/
+# More information on profiles: http://www.jhipster.tech/profiles/
+# More information on configuration properties: http://www.jhipster.tech/common-application-properties/
# ===================================================================
# ===================================================================
@@ -78,7 +78,7 @@ server:
# ===================================================================
# JHipster specific properties
#
-# Full reference is available at: https://jhipster.github.io/common-application-properties/
+# Full reference is available at: http://www.jhipster.tech/common-application-properties/
# ===================================================================
jhipster:
@@ -97,9 +97,12 @@ jhipster:
allow-credentials: true
max-age: 1800
security:
- remember-me:
- # security key (this key should be unique for your application, and kept secret)
- key: 5c37379956bd1242f5636c8cb322c2966ad81277
+ authentication:
+ jwt:
+ secret: my-secret-token-to-change-in-production
+ # Token is valid 24 hours
+ token-validity-in-seconds: 86400
+ token-validity-in-seconds-for-remember-me: 2592000
mail: # specific JHipster mail property, for standard properties see MailProperties
from: jhipsterSampleApplication@localhost
base-url: http://127.0.0.1:8080
@@ -129,7 +132,7 @@ jhipster:
# to have type-safe configuration, like in the JHipsterProperties above
#
# More documentation is available at:
-# https://jhipster.github.io/common-application-properties/
+# http://www.jhipster.tech/common-application-properties/
# ===================================================================
application:
diff --git a/src/main/resources/config/application-prod.yml b/src/main/resources/config/application-prod.yml
index 9b5472f99..99a22f792 100644
--- a/src/main/resources/config/application-prod.yml
+++ b/src/main/resources/config/application-prod.yml
@@ -3,8 +3,8 @@
#
# This configuration overrides the application.yml file.
#
-# More information on profiles: https://jhipster.github.io/profiles/
-# More information on configuration properties: https://jhipster.github.io/common-application-properties/
+# More information on profiles: http://www.jhipster.tech/profiles/
+# More information on configuration properties: http://www.jhipster.tech/common-application-properties/
# ===================================================================
# ===================================================================
@@ -78,7 +78,7 @@ server:
# ===================================================================
# JHipster specific properties
#
-# Full reference is available at: https://jhipster.github.io/common-application-properties/
+# Full reference is available at: http://www.jhipster.tech/common-application-properties/
# ===================================================================
jhipster:
@@ -91,9 +91,12 @@ jhipster:
time-to-live-seconds: 3600 # By default objects stay 1 hour in the cache
max-entries: 1000 # Number of objects in each cache entry
security:
- remember-me:
- # security key (this key should be unique for your application, and kept secret)
- key: 5c37379956bd1242f5636c8cb322c2966ad81277
+ authentication:
+ jwt:
+ secret: 07a00779cfd8d372c73b40631b62c81503e1b18e
+ # Token is valid 24 hours
+ token-validity-in-seconds: 86400
+ token-validity-in-seconds-for-remember-me: 2592000
mail: # specific JHipster mail property, for standard properties see MailProperties
from: jhipsterSampleApplication@localhost
base-url: http://my-server-url-to-change # Modify according to your server's URL
@@ -123,7 +126,7 @@ jhipster:
# to have type-safe configuration, like in the JHipsterProperties above
#
# More documentation is available at:
-# https://jhipster.github.io/common-application-properties/
+# http://www.jhipster.tech/common-application-properties/
# ===================================================================
application:
diff --git a/src/main/resources/config/application.yml b/src/main/resources/config/application.yml
index a1a46e327..7fc4272cf 100644
--- a/src/main/resources/config/application.yml
+++ b/src/main/resources/config/application.yml
@@ -4,8 +4,8 @@
# This configuration will be overridden by the Spring profile you use,
# for example application-dev.yml if you use the "dev" profile.
#
-# More information on profiles: https://jhipster.github.io/profiles/
-# More information on configuration properties: https://jhipster.github.io/common-application-properties/
+# More information on profiles: http://www.jhipster.tech/profiles/
+# More information on configuration properties: http://www.jhipster.tech/common-application-properties/
# ===================================================================
# ===================================================================
@@ -62,7 +62,7 @@ info:
# ===================================================================
# JHipster specific properties
#
-# Full reference is available at: https://jhipster.github.io/common-application-properties/
+# Full reference is available at: http://www.jhipster.tech/common-application-properties/
# ===================================================================
jhipster:
@@ -100,7 +100,7 @@ jhipster:
# to have type-safe configuration, like in the JHipsterProperties above
#
# More documentation is available at:
-# https://jhipster.github.io/common-application-properties/
+# http://www.jhipster.tech/common-application-properties/
# ===================================================================
application:
diff --git a/src/main/resources/config/liquibase/changelog/00000000000000_initial_schema.xml b/src/main/resources/config/liquibase/changelog/00000000000000_initial_schema.xml
index e9a4ca424..ade5dfce5 100644
--- a/src/main/resources/config/liquibase/changelog/00000000000000_initial_schema.xml
+++ b/src/main/resources/config/liquibase/changelog/00000000000000_initial_schema.xml
@@ -75,19 +75,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Active sessions for [{{vm.account.login}}]
-
-
- Session invalidated!
-
-
- An error has occured! The session could not be invalidated.
-
-
-
-
-
-
-
IP Address
-
User agent
-
Date
-
-
-
-
-
-
{{session.ipAddress}}
-
{{session.userAgent}}
-
{{session.tokenDate | date:'longDate'}}
-
-
-
-
-
-
-
-
diff --git a/src/main/webapp/app/account/sessions/sessions.state.js b/src/main/webapp/app/account/sessions/sessions.state.js
deleted file mode 100644
index 19f535ed2..000000000
--- a/src/main/webapp/app/account/sessions/sessions.state.js
+++ /dev/null
@@ -1,33 +0,0 @@
-(function() {
- 'use strict';
-
- angular
- .module('jhipsterSampleApplicationApp')
- .config(stateConfig);
-
- stateConfig.$inject = ['$stateProvider'];
-
- function stateConfig($stateProvider) {
- $stateProvider.state('sessions', {
- parent: 'account',
- url: '/sessions',
- data: {
- authorities: ['ROLE_USER'],
- pageTitle: 'global.menu.account.sessions'
- },
- views: {
- 'content@': {
- templateUrl: 'app/account/sessions/sessions.html',
- controller: 'SessionsController',
- controllerAs: 'vm'
- }
- },
- resolve: {
- translatePartialLoader: ['$translate', '$translatePartialLoader', function ($translate, $translatePartialLoader) {
- $translatePartialLoader.addPart('sessions');
- return $translate.refresh();
- }]
- }
- });
- }
-})();
diff --git a/src/main/webapp/app/blocks/config/http.config.js b/src/main/webapp/app/blocks/config/http.config.js
index c66ba34ce..17cf240a4 100644
--- a/src/main/webapp/app/blocks/config/http.config.js
+++ b/src/main/webapp/app/blocks/config/http.config.js
@@ -15,6 +15,7 @@
$httpProvider.interceptors.push('errorHandlerInterceptor');
$httpProvider.interceptors.push('authExpiredInterceptor');
+ $httpProvider.interceptors.push('authInterceptor');
$httpProvider.interceptors.push('notificationInterceptor');
// jhipster-needle-angularjs-add-interceptor JHipster will add new application http interceptor here
diff --git a/src/main/webapp/app/blocks/interceptor/auth-expired.interceptor.js b/src/main/webapp/app/blocks/interceptor/auth-expired.interceptor.js
index 5c8409a16..c1473fdeb 100644
--- a/src/main/webapp/app/blocks/interceptor/auth-expired.interceptor.js
+++ b/src/main/webapp/app/blocks/interceptor/auth-expired.interceptor.js
@@ -5,9 +5,9 @@
.module('jhipsterSampleApplicationApp')
.factory('authExpiredInterceptor', authExpiredInterceptor);
- authExpiredInterceptor.$inject = ['$rootScope', '$q', '$injector'];
+ authExpiredInterceptor.$inject = ['$rootScope', '$q', '$injector', '$localStorage', '$sessionStorage'];
- function authExpiredInterceptor($rootScope, $q, $injector) {
+ function authExpiredInterceptor($rootScope, $q, $injector, $localStorage, $sessionStorage) {
var service = {
responseError: responseError
};
@@ -15,18 +15,14 @@
return service;
function responseError(response) {
- // If we have an unauthorized request we redirect to the login page
- // Don't do this check on the account API to avoid infinite loop
- if (response.status === 401 && angular.isDefined(response.data.path) && response.data.path.indexOf('/api/account') === -1) {
- var Auth = $injector.get('Auth');
- var to = $rootScope.toState;
- var params = $rootScope.toStateParams;
- Auth.logout();
- if (to.name !== 'accessdenied') {
- Auth.storePreviousState(to.name, params);
+ if (response.status === 401) {
+ delete $localStorage.authenticationToken;
+ delete $sessionStorage.authenticationToken;
+ var Principal = $injector.get('Principal');
+ if (Principal.isAuthenticated()) {
+ var Auth = $injector.get('Auth');
+ Auth.authorize(true);
}
- var LoginService = $injector.get('LoginService');
- LoginService.open();
}
return $q.reject(response);
}
diff --git a/src/main/webapp/app/blocks/interceptor/auth.interceptor.js b/src/main/webapp/app/blocks/interceptor/auth.interceptor.js
new file mode 100644
index 000000000..39a3800d5
--- /dev/null
+++ b/src/main/webapp/app/blocks/interceptor/auth.interceptor.js
@@ -0,0 +1,27 @@
+(function() {
+ 'use strict';
+
+ angular
+ .module('jhipsterSampleApplicationApp')
+ .factory('authInterceptor', authInterceptor);
+
+ authInterceptor.$inject = ['$rootScope', '$q', '$location', '$localStorage', '$sessionStorage'];
+
+ function authInterceptor ($rootScope, $q, $location, $localStorage, $sessionStorage) {
+ var service = {
+ request: request
+ };
+
+ return service;
+
+ function request (config) {
+ /*jshint camelcase: false */
+ config.headers = config.headers || {};
+ var token = $localStorage.authenticationToken || $sessionStorage.authenticationToken;
+ if (token) {
+ config.headers.Authorization = 'Bearer ' + token;
+ }
+ return config;
+ }
+ }
+})();
diff --git a/src/main/webapp/app/home/home.html b/src/main/webapp/app/home/home.html
index ebb3b6508..2147c5af8 100644
--- a/src/main/webapp/app/home/home.html
+++ b/src/main/webapp/app/home/home.html
@@ -26,7 +26,7 @@