OAuth2PasswordStrategy.java
package com.guinetik.rr.auth;
import java.util.HashMap;
import java.util.Map;
/**
* Authentication strategy that implements OAuth 2.0 password flow.
* This strategy gets and refreshes OAuth 2.0 access tokens using username and password.
*/
public class OAuth2PasswordStrategy extends AbstractOAuth2Strategy {
private final String username;
private final String password;
private final String clientId;
private final String clientSecret;
private String refreshToken;
/**
* Creates a new OAuth 2.0 password strategy.
*
* @param username the user's username
* @param password the user's password
* @param clientId the OAuth 2.0 client ID (optional, can be null)
* @param clientSecret the OAuth 2.0 client secret (optional, can be null)
* @param tokenUrl the OAuth 2.0 token endpoint URL
*/
public OAuth2PasswordStrategy(String username, String password, String clientId, String clientSecret, String tokenUrl) {
this(username, password, clientId, clientSecret, tokenUrl, new HashMap<>());
}
/**
* Creates a new OAuth 2.0 password strategy with additional parameters.
*
* @param username the user's username
* @param password the user's password
* @param clientId the OAuth 2.0 client ID (optional, can be null)
* @param clientSecret the OAuth 2.0 client secret (optional, can be null)
* @param tokenUrl the OAuth 2.0 token endpoint URL
* @param additionalParams additional parameters to include in the token request
*/
public OAuth2PasswordStrategy(String username, String password, String clientId, String clientSecret,
String tokenUrl,
Map<String, String> additionalParams) {
super(tokenUrl, additionalParams);
this.username = username;
this.password = password;
this.clientId = clientId;
this.clientSecret = clientSecret;
}
@Override
public AuthType getType() {
return AuthType.OAUTH_PASSWORD;
}
/**
* {@inheritDoc}
* @throws TokenRefreshException if the username or password is not provided.
*/
@Override
protected void validateCredentials() {
if (username == null || password == null) {
throw new TokenRefreshException("Username and Password are required for OAuth2 password flow");
}
}
/**
* {@inheritDoc}
* <p>
* Prepares parameters for the OAuth 2.0 password grant type or refresh token grant type.
* If a refresh token is available, it will be used. Otherwise, username and password will be used.
* Client ID and client secret are included if provided.
*/
@Override
protected Map<String, String> prepareTokenRequestParams() {
Map<String, String> formParams = new HashMap<>();
// If we have a refresh token, use that; otherwise, use password flow
if (this.refreshToken != null && !this.refreshToken.isEmpty()) {
formParams.put("grant_type", "refresh_token");
formParams.put("refresh_token", this.refreshToken);
} else {
formParams.put("grant_type", "password");
formParams.put("username", username);
formParams.put("password", password);
}
// Add client credentials if provided
if (clientId != null && !clientId.isEmpty()) {
formParams.put("client_id", clientId);
if (clientSecret != null && !clientSecret.isEmpty()) {
formParams.put("client_secret", clientSecret);
}
}
return formParams;
}
/**
* {@inheritDoc}
* <p>
* Processes the token response, extracting and storing the refresh_token if present,
* in addition to the access_token and expiry time handled by the superclass.
*/
@Override
protected boolean processTokenResponse(Map<String, Object> tokenResponse) {
Object refreshTokenObj = tokenResponse.get("refresh_token");
// Update refresh token if provided
if (refreshTokenObj != null) {
this.refreshToken = refreshTokenObj.toString();
}
// Let the parent class handle the rest
return super.processTokenResponse(tokenResponse);
}
/**
* Gets the current refresh token.
*
* @return the current refresh token, or null if not yet obtained
*/
public String getRefreshToken() {
return refreshToken;
}
}