Add first version of token generation.

This commit is contained in:
Paulo Gustavo Veiga
2024-02-04 18:28:23 -08:00
parent 6674c607f7
commit 069943cf30
10 changed files with 653 additions and 7 deletions

View File

@@ -32,6 +32,7 @@ public class RestAppConfig {
.securityMatcher("/**")
.authorizeHttpRequests(auth -> auth
.requestMatchers(mvc.pattern("/api/restfull/users/")).permitAll()
.requestMatchers(mvc.pattern("/api/restfull/authenticate")).permitAll()
.requestMatchers(mvc.pattern("/api/restfull/users/resetPassword")).permitAll()
.requestMatchers(mvc.pattern("/api/restfull/oauth2/googlecallback")).permitAll()
.requestMatchers(mvc.pattern("/api/restfull/oauth2/confirmaccountsync")).permitAll()

View File

@@ -0,0 +1,75 @@
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.rest;
import com.wisemapping.rest.model.RestJwtUser;
import com.wisemapping.security.JwtTokenUtil;
import com.wisemapping.security.UserDetailsService;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
@CrossOrigin
@RequestMapping("/api/restfull")
public class JwtAuthController {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@RequestMapping(value = "/authenticate", method = RequestMethod.POST)
public ResponseEntity<?> createAuthenticationToken(@RequestBody RestJwtUser user) throws Exception {
// Is a valid user ?
authenticate(user.getUsername(), user.getPassword());
// Create token ...
final UserDetails userDetails = userDetailsService
.loadUserByUsername(user.getUsername());
final String token = jwtTokenUtil.generateJwtToken(userDetails);
return ResponseEntity.ok(token);
}
private void authenticate(@NotNull String username, @NotNull String password) throws Exception {
try {
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
} catch (DisabledException e) {
throw new Exception("USER_DISABLED", e);
} catch (BadCredentialsException e) {
throw new Exception("INVALID_CREDENTIALS", e);
}
}
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.rest.model;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import org.jetbrains.annotations.NotNull;
@JsonAutoDetect(
fieldVisibility = JsonAutoDetect.Visibility.NONE,
getterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY,
isGetterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY)
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public class RestJwtUser {
private String username;
private String password;
public RestJwtUser(@NotNull String username, @NotNull String password) {
this.setUsername(username);
this.setPassword(password);
}
public String getUsername() {
return this.username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
}

View File

@@ -0,0 +1,61 @@
package com.wisemapping.security;
import io.jsonwebtoken.*;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import java.io.Serializable;
import java.security.Key;
import java.util.Date;
@Component
public class JwtTokenUtil implements Serializable {
final private Logger logger = LogManager.getLogger();
@Value("${app.jwt.secret}")
private String jwtSecret;
@Value("${app.jwt.expirationMs}")
private int jwtExpirationMs;
public String generateJwtToken(@NotNull final UserDetails user) {
return Jwts.builder()
.setSubject((user.getUsername()))
.setIssuedAt(new Date())
.setExpiration(new Date((new Date()).getTime() + jwtExpirationMs))
.signWith(key(), SignatureAlgorithm.HS256)
.compact();
}
private Key key() {
return Keys.hmacShaKeyFor(Decoders.BASE64.decode(jwtSecret));
}
public String getUserNameFromJwtToken(String token) {
return Jwts.parserBuilder().setSigningKey(key()).build()
.parseClaimsJws(token).getBody().getSubject();
}
public boolean validateJwtToken(String authToken) {
try {
Jwts.parserBuilder().setSigningKey(key()).build().parse(authToken);
return true;
} catch (MalformedJwtException e) {
logger.error("Invalid JWT token: {}", e.getMessage());
} catch (ExpiredJwtException e) {
logger.error("JWT token is expired: {}", e.getMessage());
} catch (UnsupportedJwtException e) {
logger.error("JWT token is unsupported: {}", e.getMessage());
} catch (IllegalArgumentException e) {
logger.error("JWT claims string is empty: {}", e.getMessage());
}
return false;
}
}

View File

@@ -36,7 +36,7 @@ public class UserDetailsService
@Autowired
private UserService userService;
@Value("${admin.user}")
@Value("${app.admin.user}")
private String adminUser;
@Override

View File

@@ -54,7 +54,7 @@ public class MindmapServiceImpl
@Autowired
private NotificationService notificationService;
@Value("${admin.user}")
@Value("${app.admin.user}")
private String adminUser;
final private LockManager lockManager;

View File

@@ -31,11 +31,13 @@ spring:
# Application Configuration.
admin:
user: admin@wisemapping.org
database:
base:
url: /Users/veigap/
app:
jwt:
secret: dlqxKAg685SaKhsQXIMeM=JWCw3bkl3Ei3Tb7LMlnd19oMd66burPNlJ0Po1qguyjgpakQTk2CN3
expirationMs: 10000
admin:
user: admin@wisemapping.org
google:
ads:
enabled: false