Skip to content

Commit 94ddc41

Browse files
author
Sherzod Mamadaliev
authored
Add additional service for security #60
2 parents 6ff4402 + 254f212 commit 94ddc41

File tree

8 files changed

+139
-67
lines changed

8 files changed

+139
-67
lines changed

src/main/java/com/reckue/account/controller/AccountController.java

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,17 @@
33
import com.reckue.account.controller.api.AccountApi;
44
import com.reckue.account.exception.AuthenticationException;
55
import com.reckue.account.service.AccountService;
6+
import com.reckue.account.service.SecurityService;
67
import com.reckue.account.transfer.AccountTransfer;
78
import lombok.RequiredArgsConstructor;
89
import lombok.extern.slf4j.Slf4j;
910
import org.dozer.Mapper;
10-
import org.springframework.http.HttpStatus;
1111
import org.springframework.web.bind.annotation.*;
1212

1313
import javax.servlet.http.HttpServletRequest;
1414
import java.util.List;
1515
import java.util.stream.Collectors;
1616

17-
import static org.springframework.http.HttpHeaders.AUTHORIZATION;
18-
1917
/**
2018
* Class AccountController represents a REST-Controller with get and delete operations connecting with users.
2119
*
@@ -30,6 +28,7 @@ public class AccountController implements AccountApi {
3028

3129
private final Mapper mapper;
3230
private final AccountService accountService;
31+
private final SecurityService securityService;
3332

3433
/**
3534
* This type of request allows to get all the users that meet the requirements.
@@ -80,32 +79,24 @@ public AccountTransfer getByUsername(@PathVariable String username) {
8079
* Throws {@link AuthenticationException} in case if token is absent.
8180
*
8281
* @param id the object identifier
82+
* @param request information for HTTP servlets
8383
*/
8484
@DeleteMapping("/delete/id/{id}")
8585
// @PreAuthorize("hasRole('ROLE_ADMIN')") doesn't work
8686
public void deleteById(@PathVariable String id, HttpServletRequest request) {
87-
try {
88-
String token = request.getHeader(AUTHORIZATION).substring(7);
89-
accountService.deleteById(id, token);
90-
} catch (NullPointerException e) {
91-
throw new AuthenticationException("Token missing", HttpStatus.BAD_REQUEST);
92-
}
87+
accountService.deleteById(id, securityService.checkAndGetInfo(request));
9388
}
9489

9590
/**
9691
* This type of request allows to delete the account by name.
9792
* Throws {@link AuthenticationException} in case if token is absent.
9893
*
9994
* @param username the object name
95+
* @param request information for HTTP servlets
10096
*/
10197
@DeleteMapping("/delete/username/{username}")
10298
// @PreAuthorize("hasRole('ROLE_ADMIN')") doesn't work
10399
public void deleteByUsername(@PathVariable String username, HttpServletRequest request) {
104-
try {
105-
String token = request.getHeader(AUTHORIZATION).substring(7);
106-
accountService.deleteByUsername(username, token);
107-
} catch (NullPointerException e) {
108-
throw new AuthenticationException("Token missing", HttpStatus.BAD_REQUEST);
109-
}
100+
accountService.deleteByUsername(username, securityService.checkAndGetInfo(request));
110101
}
111102
}

src/main/java/com/reckue/account/controller/AuthController.java

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
import com.reckue.account.controller.api.AuthApi;
44
import com.reckue.account.exception.AuthenticationException;
55
import com.reckue.account.service.AuthService;
6+
import com.reckue.account.service.SecurityService;
67
import com.reckue.account.transfer.AccountTransfer;
78
import com.reckue.account.transfer.RegisterRequest;
89
import io.swagger.annotations.ApiParam;
910
import lombok.RequiredArgsConstructor;
1011
import org.dozer.Mapper;
11-
import org.springframework.http.HttpStatus;
1212
import org.springframework.http.ResponseEntity;
1313
import org.springframework.security.access.prepost.PreAuthorize;
1414
import org.springframework.security.oauth2.common.OAuth2AccessToken;
@@ -21,8 +21,6 @@
2121
import java.util.HashMap;
2222
import java.util.Map;
2323

24-
import static org.springframework.http.HttpHeaders.AUTHORIZATION;
25-
2624
/**
2725
* Class AuthСontroller represents a REST-Controller with post and get operations connection with authentication.
2826
*
@@ -37,6 +35,7 @@ public class AuthController implements AuthApi {
3735
private final Mapper mapper;
3836
private final AuthService authService;
3937
private final TokenEndpoint tokenEndpoint;
38+
private final SecurityService securityService;
4039

4140
/**
4241
* This type of request allows to register a new account.
@@ -45,9 +44,8 @@ public class AuthController implements AuthApi {
4544
* @return string
4645
*/
4746
@PostMapping("/register")
48-
public String register(@RequestBody RegisterRequest registerForm) {
49-
authService.register(registerForm);
50-
return "You have successfully registered";
47+
public AccountTransfer register(@RequestBody RegisterRequest registerForm) {
48+
return mapper.map(authService.register(registerForm), AccountTransfer.class);
5149
}
5250

5351
/**
@@ -99,13 +97,7 @@ public ResponseEntity<OAuth2AccessToken> getToken(Principal principal,
9997
@GetMapping(value = "/current")
10098
@PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER')")
10199
public AccountTransfer getCurrentUser(HttpServletRequest request) {
102-
try {
103-
String token = request.getHeader(AUTHORIZATION).substring(7);
104-
return mapper.map(authService.getCurrentUser(token), AccountTransfer.class);
105-
} catch (NullPointerException e) {
106-
throw new AuthenticationException("Token missing", HttpStatus.BAD_REQUEST);
107-
} catch (StringIndexOutOfBoundsException e) {
108-
throw new AuthenticationException("Token is too short", HttpStatus.BAD_REQUEST);
109-
}
100+
return mapper.map(authService.getCurrentUser(
101+
(String) securityService.checkAndGetInfo(request).get("userId")), AccountTransfer.class);
110102
}
111103
}

src/main/java/com/reckue/account/controller/api/AuthApi.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
import com.reckue.account.transfer.AccountTransfer;
44
import com.reckue.account.transfer.RegisterRequest;
55
import io.swagger.annotations.*;
6+
import org.springframework.http.HttpStatus;
67
import org.springframework.http.ResponseEntity;
78
import org.springframework.security.oauth2.common.OAuth2AccessToken;
89
import org.springframework.web.HttpRequestMethodNotSupportedException;
10+
import org.springframework.web.bind.annotation.ResponseStatus;
911

1012
import javax.servlet.http.HttpServletRequest;
1113
import java.security.Principal;
@@ -24,27 +26,26 @@ public interface AuthApi {
2426
@ApiResponse(code = 201, message = "Register form has created"),
2527
@ApiResponse(code = 400, message = "You need to change the incoming parameters"),
2628
@ApiResponse(code = 500, message = "Access to the resource you tried to obtain is not possible")})
27-
String register(RegisterRequest registerForm);
29+
@ResponseStatus(code = HttpStatus.CREATED)
30+
AccountTransfer register(RegisterRequest registerForm);
2831

2932
@ApiOperation(value = "Authorization", response = OAuth2AccessToken.class)
3033
@ApiResponses(value = {
31-
@ApiResponse(code = 202, message = "JWT has created"),
34+
@ApiResponse(code = 201, message = "JWT has created"),
3235
@ApiResponse(code = 400, message = "You need to change the incoming parameters"),
33-
@ApiResponse(code = 401, message = "Unauthorized"),
34-
@ApiResponse(code = 403, message = "Forbidden"),
3536
@ApiResponse(code = 404, message = "The account by this username is not found"),
3637
@ApiResponse(code = 500, message = "Access to the resource you tried to obtain is not possible")})
38+
@ResponseStatus(code = HttpStatus.CREATED)
3739
ResponseEntity<OAuth2AccessToken> getToken(Principal principal, String scope, String grantType, String username,
3840
String password, String refreshToken) throws HttpRequestMethodNotSupportedException;
3941

4042

4143
@ApiOperation(value = "Get current user", response = AccountTransfer.class,
4244
authorizations = {@Authorization(value = "Bearer token")})
4345
@ApiResponses(value = {
44-
@ApiResponse(code = 202, message = "The request has accepted"),
46+
@ApiResponse(code = 200, message = "The request has completed"),
4547
@ApiResponse(code = 400, message = "You need to change the incoming parameters"),
4648
@ApiResponse(code = 401, message = "Unauthorized"),
47-
@ApiResponse(code = 403, message = "Forbidden"),
4849
@ApiResponse(code = 404, message = "The account by this username is not found"),
4950
@ApiResponse(code = 500, message = "Access to the resource you tried to obtain is not possible")})
5051
AccountTransfer getCurrentUser(HttpServletRequest request);

src/main/java/com/reckue/account/service/AccountService.java

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import org.springframework.data.domain.Sort;
1616
import org.springframework.http.HttpStatus;
1717
import org.springframework.security.crypto.password.PasswordEncoder;
18-
import org.springframework.security.oauth2.provider.token.TokenStore;
1918
import org.springframework.stereotype.Service;
2019
import org.springframework.transaction.annotation.Transactional;
2120

@@ -38,7 +37,6 @@ public class AccountService {
3837

3938
private final AccountRepository accountRepository;
4039
private final PasswordEncoder passwordEncoder;
41-
private final TokenStore tokenStore;
4240

4341
/**
4442
* This method is used to find all the users in the database that meet the requirements.
@@ -100,13 +98,13 @@ public Account create(Account accountModel) {
10098
* Throws {@link AccessDeniedException} in case if the user isn't the same user or
10199
* hasn't admin authorities.
102100
*
103-
* @param username the object name
101+
* @param username the object name
102+
* @param tokenInfo additional information from a token
104103
*/
105-
public void deleteByUsername(String username, String token) {
104+
public void deleteByUsername(String username, Map<String, Object> tokenInfo) {
106105
if (!accountRepository.existsByUsername(username)) {
107106
throw new NotFoundException("The account by username '" + username + "' not found", HttpStatus.NOT_FOUND);
108107
}
109-
Map<String, Object> tokenInfo = tokenStore.readAccessToken(token).getAdditionalInformation();
110108
Optional<Account> account = accountRepository.findByUsername(username);
111109
if (account.isPresent()) {
112110
String userId = account.get().getId();
@@ -124,13 +122,13 @@ public void deleteByUsername(String username, String token) {
124122
* Throws {@link AccessDeniedException} in case if the user isn't the same user or
125123
* hasn't admin authorities.
126124
*
127-
* @param id the object identifier
125+
* @param id the object identifier
126+
* @param tokenInfo additional information from a token
128127
*/
129-
public void deleteById(String id, String token) {
128+
public void deleteById(String id, Map<String, Object> tokenInfo) {
130129
if (!accountRepository.existsById(id)) {
131130
throw new NotFoundException("The account by id '" + id + "' not found", HttpStatus.NOT_FOUND);
132131
}
133-
Map<String, Object> tokenInfo = tokenStore.readAccessToken(token).getAdditionalInformation();
134132
Optional<Account> account = accountRepository.findById(id);
135133
if (account.isPresent()) {
136134
String userId = account.get().getId();

src/main/java/com/reckue/account/service/AuthService.java

Lines changed: 10 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
import org.springframework.http.ResponseEntity;
1717
import org.springframework.security.crypto.password.PasswordEncoder;
1818
import org.springframework.security.oauth2.common.OAuth2AccessToken;
19-
import org.springframework.security.oauth2.provider.token.TokenStore;
2019
import org.springframework.stereotype.Service;
2120
import org.springframework.transaction.annotation.Transactional;
2221

@@ -33,7 +32,6 @@
3332
@RequiredArgsConstructor
3433
public class AuthService {
3534

36-
private final TokenStore tokenStore;
3735
private final AccountRepository accountRepository;
3836
private final PasswordEncoder passwordEncoder;
3937

@@ -44,7 +42,7 @@ public class AuthService {
4442
* @param registerForm with required fields
4543
*/
4644
@Transactional
47-
public void register(RegisterRequest registerForm) {
45+
public Account register(RegisterRequest registerForm) {
4846
// todo: send a mail about registration to user email
4947
//checking that the account exists in the database
5048
if (!accountRepository.existsByUsername(registerForm.getUsername())) {
@@ -77,7 +75,7 @@ public void register(RegisterRequest registerForm) {
7775
account.getRoles().add(new Role("ROLE_USER"));
7876

7977
// save the account in database
80-
accountRepository.save(account);
78+
return accountRepository.save(account);
8179

8280
} else {
8381
throw new AuthenticationException("Username already exists", HttpStatus.BAD_REQUEST);
@@ -111,28 +109,17 @@ public void saveAndCheckRefreshToken(ResponseEntity<OAuth2AccessToken> responseE
111109
/**
112110
* This method is used to get the account by user token.
113111
* Throws {@link NotFoundException} in case if such account isn't contained in database.
114-
* Throws {@link AuthenticationException} in case of invalid token.
115112
*
116-
* @param token user token
113+
* @param userId token user id
117114
* @return the object of class AccountTransfer
118115
*/
119-
public Account getCurrentUser(String token) {
120-
// get userId from jwt token
121-
try {
122-
String userId = (String) tokenStore.readAccessToken(token).getAdditionalInformation().get("userId");
123-
124-
// find account by username from database
125-
Account account = accountRepository.findById(userId)
126-
.orElseThrow(() -> new NotFoundException("The account by id [" + userId + "] not found",
127-
HttpStatus.NOT_FOUND));
128-
129-
// update last visit date
130-
account.setLastVisit(TimestampHelper.getCurrentTimestamp());
131-
132-
return account;
133-
} catch (Exception e) {
134-
throw new AuthenticationException("Invalid token", HttpStatus.UNAUTHORIZED);
135-
}
116+
public Account getCurrentUser(String userId) {
117+
Account account = accountRepository.findById(userId)
118+
.orElseThrow(() -> new NotFoundException("The account by id [" + userId + "] not found",
119+
HttpStatus.NOT_FOUND));
120+
// update last visit date
121+
account.setLastVisit(TimestampHelper.getCurrentTimestamp());
122+
return account;
136123

137124
}
138125
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.reckue.account.service;
2+
3+
import com.reckue.account.exception.AuthenticationException;
4+
5+
import javax.servlet.http.HttpServletRequest;
6+
import java.util.Map;
7+
8+
/**
9+
* Class SecurityService represents the service for work with token.
10+
*
11+
* @author Kamila Meshcheryakova
12+
*/
13+
public interface SecurityService {
14+
15+
/**
16+
* The default realization of the algorithm:
17+
* check token and get additional information from a token.
18+
*
19+
* @param request information for HTTP servlets
20+
* @return additional information from token
21+
*/
22+
default Map<String, Object> checkAndGetInfo(HttpServletRequest request) throws AuthenticationException {
23+
return getTokenInfo(checkToken(request));
24+
}
25+
26+
/**
27+
* The method allows to get all additional information from a token.
28+
*
29+
* @param token user token
30+
* @return additional information from a token
31+
*/
32+
Map<String, Object> getTokenInfo(String token);
33+
34+
/**
35+
* The method allows to check for token availability.
36+
*
37+
* @param request information for HTTP servlets
38+
* @return access token
39+
*/
40+
String checkToken(HttpServletRequest request);
41+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package com.reckue.account.service.impl;
2+
3+
import com.reckue.account.exception.AuthenticationException;
4+
import com.reckue.account.service.SecurityService;
5+
import lombok.RequiredArgsConstructor;
6+
import org.springframework.http.HttpStatus;
7+
import org.springframework.security.oauth2.provider.token.TokenStore;
8+
import org.springframework.stereotype.Service;
9+
10+
import javax.servlet.http.HttpServletRequest;
11+
import java.util.Map;
12+
13+
import static org.springframework.http.HttpHeaders.AUTHORIZATION;
14+
15+
/**
16+
* Class SecurityServiceImpl represents realization of SecurityService.
17+
*
18+
* @author Kamila Meshcheryakova
19+
*/
20+
@Service
21+
@RequiredArgsConstructor
22+
public class SecurityServiceImpl implements SecurityService {
23+
24+
private final TokenStore tokenStore;
25+
26+
/**
27+
* The method allows to get all additional information from a token.
28+
* Throws {@link AuthenticationException} in case of invalid token.
29+
*
30+
* @param token user token
31+
* @return additional information from a token
32+
*/
33+
@Override
34+
public Map<String, Object> getTokenInfo(String token) {
35+
try {
36+
return tokenStore.readAccessToken(token).getAdditionalInformation();
37+
} catch (Exception e) {
38+
throw new AuthenticationException("Invalid token", HttpStatus.UNAUTHORIZED);
39+
}
40+
}
41+
42+
/**
43+
* The method allows to check for token availability.
44+
* Throws {@link AuthenticationException} in case if the token is missing or
45+
* is too short.
46+
*
47+
* @param request information for HTTP servlets
48+
* @return access token
49+
*/
50+
@Override
51+
public String checkToken(HttpServletRequest request) {
52+
String token;
53+
try {
54+
token = request.getHeader(AUTHORIZATION).substring(7);
55+
return token;
56+
} catch (NullPointerException e) {
57+
throw new AuthenticationException("Token missing", HttpStatus.BAD_REQUEST);
58+
} catch (StringIndexOutOfBoundsException e) {
59+
throw new AuthenticationException("Token is too short", HttpStatus.BAD_REQUEST);
60+
}
61+
}
62+
}

0 commit comments

Comments
 (0)