Question
I have been honing this UMS, and need to double-check functionality. Instructions for service that needs to be created: You need to build the OAuth
I have been honing this UMS, and need to double-check functionality.
Instructions for service that needs to be created:
You need to build the OAuth 2.0 Authorization Code Grant Flow in accordance with RFC 6749.
As an Authorization Server you will be using GitHub, all other services will be your own, working on your localhost.
Need to create UserManagementService in such a way that it will generate a token based on data, obtained from the Authorization Provider (in this particular case it is GitHub) after a user tries to log in.
Once you have received the user data, the UserManagementService must generate a simple UUID token, correlated to the user logged in, and store that token inside the UMS database until the user logs in, or until the session expires (lets say 15 minutes).
In the next step, when the user tries to reach API of another service, the user will provide that token as part of the request and another service will ask the UserManagementService the following questions (through another call to UMS):
Whether that token valid (not expired);
If yes, which role is that token associated with.
At the end of this, depending on the UMSs response, the target service should either perform the request or return a 401 status.
After an edit earlier today, here is what I now have:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.RowMapper; import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.JWTVerificationException; import com.auth0.jwt.interfaces.DecodedJWT;
@Service public class JwtUserManagementService implements UserManagementService { private final JdbcTemplate jdbcTemplate; @Autowired public JwtUserManagementService(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } @Override public void storeToken(String username, String token) { String sql = "INSERT INTO user_tokens (username, token) VALUES (?, ?) " + "ON DUPLICATE KEY UPDATE token = ?"; jdbcTemplate.update(sql, username, token, token); } @Override public String getUsernameFromToken(String token) { DecodedJWT decodedJWT = JWT.decode(token); return decodedJWT.getSubject(); } @Override public User getUserFromToken(String token) { String username = getUsernameFromToken(token); String sql = "SELECT * FROM users WHERE username = ?"; return jdbcTemplate.queryForObject(sql, new Object[]{username}, new UserRowMapper()); } @Override public boolean isTokenValid(String token) { try { Algorithm algorithm = Algorithm.HMAC256("secret"); JWTVerifier verifier = JWT.require(algorithm).build(); verifier.verify(token); return true; } catch (JWTVerificationException e) { return false; } } @Override public User createUser(String username, String password, String email) { String sql = "INSERT INTO users (username, password, email) VALUES (?, ?, ?)"; jdbcTemplate.update(sql, username, password, email); return new User(username, password, email); } @Override public User updateUser(User user) { String sql = "UPDATE users SET password = ?, email = ? WHERE username = ?"; jdbcTemplate.update(sql, user.getPassword(), user.getEmail(), user.getUsername()); return user; } @Override public void deleteUser(User user) { String sql = "DELETE FROM users WHERE username = ?"; jdbcTemplate.update(sql, user.getUsername()); } @Override public List
public class UserRowMapper implements RowMapper
package com.mycompany.chirper;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService; import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.client.RestTemplate;
@Controller public class OAuthController {
private final UserManagementService userManagementService; private final OAuth2AuthorizedClientService authorizedClientService;
// Constructor injection public OAuthController(UserManagementService userManagementService, OAuth2AuthorizedClientService authorizedClientService) { this.userManagementService = userManagementService; this.authorizedClientService = authorizedClientService; }
@GetMapping("/login/oauth2/code/github") public String handleGitHubCallback(@RequestParam("code") String code, OAuth2AuthenticationToken authentication) { // Exchange code for access token String accessToken = exchangeCodeForAccessToken(code, authentication);
// Extract user information from GitHub using the access token String username = extractUsernameFromGitHub(accessToken);
// Generate and store a token in UserManagementService String token = userManagementService.generateToken(username);
// Store the token in the UserManagementService database userManagementService.storeToken(username, token);
// Redirect or respond as needed return "redirect:/"; }
private String exchangeCodeForAccessToken(String code, OAuth2AuthenticationToken authentication) { String clientRegistrationId = authentication.getAuthorizedClientRegistrationId(); OAuth2AuthorizedClient authorizedClient = authorizedClientService.loadAuthorizedClient(clientRegistrationId, authentication.getName()); String tokenUri = authorizedClient.getClientRegistration().getProviderDetails().getTokenUri();
// Prepare the request to exchange code for access token RestTemplate restTemplate = new RestTemplate(); String requestBody = "code=" + code + "&client_id=" + authorizedClient.getClientRegistration().getClientId() + "&client_secret=" + authorizedClient.getClientRegistration().getClientSecret() + "&redirect_uri=" + authorizedClient.getClientRegistration().getRedirectUri() + "&grant_type=authorization_code";
// Make the request to the token endpoint AccessTokenResponse response = restTemplate.postForObject(tokenUri, requestBody, AccessTokenResponse.class); if (response != null) { return response.getAccessToken(); } else { throw new RuntimeException("Failed to exchange code for access token"); } }
private String extractUsernameFromGitHub(String accessToken) { // Prepare the request to retrieve user information from GitHub RestTemplate restTemplate = new RestTemplate(); String apiUrl = "Placeholder for GitHub API URL"; String authorizationHeader = "Bearer " + accessToken;
// Set the authorization header HttpHeaders headers = new HttpHeaders(); headers.set("Authorization", authorizationHeader); HttpEntity
// Make the request to the GitHub API ResponseEntity
package com.mycompany.chirper;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController;
@RestController public class MyApiController {
private final UserManagementService userManagementService;
// Constructor injection public MyApiController(UserManagementService userManagementService) { this.userManagementService = userManagementService; }
@GetMapping("/api/user") @PreAuthorize("hasAuthority('ROLE_USER')") public String secureApiEndpoint(@RequestParam("token") String token) { // Check if the token is valid if (userManagementService.isTokenValid(token)) { // Get user roles from UMS List
// Check if the user has the required role if (roles.contains("ROLE_USER")) { // Your API logic Please assist with this section return "Hello, authenticated user!"; } }
// If the token is not valid or the user doesn't have the required role // Return a 401 status or handle the unauthorized request accordingly return "Unauthorized"; } }
package com.mycompany.chirper;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository;
import java.util.List;
@Repository public interface UserRepository extends JpaRepository
package com.mycompany.chirper;
import org.springframework.stereotype.Component;
@Component public class AccessTokenResponse { private String accessToken;
public String getAccessToken() { return accessToken; }
public void setAccessToken(String accessToken) { this.accessToken = accessToken; } }
public class ApiError { private HttpStatus status; private String message; public ApiError(HttpStatus status, String message) { this.status = status; this.message = message; } public HttpStatus getStatus() { return status; } public String getMessage() { return message; } }
Am I missing anything else for these requirements?
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started