Answered step by step
Verified Expert Solution
Link Copied!

Question

1 Approved Answer

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 getAllUsers() { String sql = "SELECT * FROM users"; return jdbcTemplate.query(sql, new UserRowMapper()); } @Override public List searchUsers(String keyword) { String sql = "SELECT * FROM users WHERE username LIKE ?"; return jdbcTemplate.query(sql, new Object[]{"%" + keyword + "%"}, new UserRowMapper()); } }

public class UserRowMapper implements RowMapper { @Override public User mapRow(ResultSet rs, int rowNum) throws SQLException { String username = rs.getString("username"); String password = rs.getString("password"); String email = rs.getString("email"); return new User(username, password, email); } }

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 entity = new HttpEntity<>(headers);

// Make the request to the GitHub API ResponseEntity response = restTemplate.exchange(apiUrl, HttpMethod.GET, entity, Map.class); if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) { Map responseBody = response.getBody(); return responseBody.get("login").toString(); } else { throw new RuntimeException("Failed to retrieve user information from GitHub"); } } }

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 roles = userManagementService.getUserRoles(token);

// 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 { User findByUsername(String username); User findByEmail(String email); List findByFirstName(String firstName); List findByLastName(String lastName); void deleteByUsername(String username); }

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

blur-text-image

Get Instant Access to Expert-Tailored Solutions

See step-by-step solutions with expert insights and AI powered tools for academic success

Step: 2

blur-text-image

Step: 3

blur-text-image

Ace Your Homework with AI

Get the answers you need in no time with our AI-driven, step-by-step assistance

Get Started

Recommended Textbook for

Databases Illuminated

Authors: Catherine M Ricardo, Susan D Urban

3rd Edition

1284056945, 9781284056945

More Books

Students also viewed these Databases questions