forked from justauth/JustAuth
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
261 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
66 changes: 66 additions & 0 deletions
66
src/main/java/me/zhyd/oauth/enums/scope/AuthOktaScope.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package me.zhyd.oauth.enums.scope; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
|
||
/** | ||
* Okta 平台 OAuth 授权范围 | ||
* | ||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com) | ||
* @since 1.16.0 | ||
*/ | ||
@Getter | ||
@AllArgsConstructor | ||
public enum AuthOktaScope implements AuthScope { | ||
|
||
/** | ||
* {@code scope} 含义,以{@code description} 为准 | ||
*/ | ||
OPENID("openid", "Signals that a request is an OpenID request.", true), | ||
PROFILE("profile", "The exact data varies based on what profile information you have provided, such as: name, time zone, picture, or birthday.", true), | ||
EMAIL("email", "This allows the app to view your email address.", true), | ||
ADDRESS("address", "This allows the app to view your address, such as: street address, city, state, and zip code.", true), | ||
PHONE("phone", "This allows the app to view your phone number.", true), | ||
OFFLINE_ACCESS("offline_access", "This keeps you signed in to the app, even when you are not using it.", true), | ||
OKTA_USERS_MANAGE("okta.users.manage", "Allows the app to create and manage users and read all profile and credential information for users", false), | ||
OKTA_USERS_READ("okta.users.read", "Allows the app to read any user's profile and credential information", false), | ||
OKTA_USERS_MANAGE_SELF("okta.users.manage.self", "Allows the app to manage the currently signed-in user's profile. Currently only supports user profile attribute updates.", false), | ||
OKTA_USERS_READ_SELF("okta.users.read.self", "Allows the app to read the currently signed-in user's profile and credential information", false), | ||
OKTA_APPS_MANAGE("okta.apps.manage", "Allows the app to create and manage Apps in your Okta organization", false), | ||
OKTA_APPS_READ("okta.apps.read", "Allows the app to read information about Apps in your Okta organization", false), | ||
OKTA_AUTHORIZATIONSERVERS_MANAGE("okta.authorizationServers.manage", "Allows the app to manage authorization servers", false), | ||
OKTA_AUTHORIZATIONSERVERS_READ("okta.authorizationServers.read", "Allows the app to read authorization server information", false), | ||
OKTA_CLIENTS_MANAGE("okta.clients.manage", "Allows the app to manage all OAuth/OIDC clients and to create new clients", false), | ||
OKTA_CLIENTS_READ("okta.clients.read", "Allows the app to read information for all OAuth/OIDC clients", false), | ||
OKTA_CLIENTS_REGISTER("okta.clients.register", "Allows the app to register (create) new OAuth/OIDC clients (but not read information about existing clients)", false), | ||
OKTA_EVENTHOOKS_MANAGE("okta.eventHooks.manage", "Allows the app to create and manage Event Hooks in your Okta organization", false), | ||
OKTA_EVENTHOOKS_READ("okta.eventHooks.read", "Allows the app to read information about Event Hooks in your Okta organization", false), | ||
OKTA_FACTORS_MANAGE("okta.factors.manage", "Allows the app to manage all admin operations for org factors (for example, activate, deactive, read)", false), | ||
OKTA_FACTORS_READ("okta.factors.read", "Allows the app to read org factors information", false), | ||
OKTA_GROUPS_MANAGE("okta.groups.manage", "Allows the app to manage groups in your Okta organization", false), | ||
OKTA_GROUPS_READ("okta.groups.read", "Allows the app to read information about groups and their members in your Okta organization", false), | ||
OKTA_IDPS_MANAGE("okta.idps.manage", "Allows the app to create and manage Identity Providers in your Okta organization", false), | ||
OKTA_IDPS_READ("okta.idps.read", "Allows the app to read information about Identity Providers in your Okta organization", false), | ||
OKTA_INLINEHOOKS_MANAGE("okta.inlineHooks.manage", "Allows the app to create and manage Inline Hooks in your Okta organization.", false), | ||
OKTA_INLINEHOOKS_READ("okta.inlineHooks.read", "Allows the app to read information about Inline Hooks in your Okta organization.", false), | ||
OKTA_LINKEDOBJECTS_MANAGE("okta.linkedObjects.manage", "Allows the app to manage Linked Object definitions in your Okta organization.", false), | ||
OKTA_LINKEDOBJECTS_READ("okta.linkedObjects.read", "Allows the app to read Linked Object definitions in your Okta organization.", false), | ||
OKTA_LOGS_READ("okta.logs.read", "Allows the app to read information about System Log entries in your Okta organization", false), | ||
OKTA_ROLES_MANAGE("okta.roles.manage", "Allows the app to create and manage Administrator Roles in your Okta organization", false), | ||
OKTA_ROLES_READ("okta.roles.read", "Allows the app to read information about Administrator Roles in your Okta organization", false), | ||
OKTA_SCHEMAS_MANAGE("okta.schemas.manage", "Allows the app to create and manage Schemas in your Okta organization", false), | ||
OKTA_SCHEMAS_READ("okta.schemas.read", "Allows the app to read information about Schemas in your Okta organization", false), | ||
OKTA_SESSIONS_MANAGE("okta.sessions.manage", "Allows the app to manage all sessions in your Okta organization", false), | ||
OKTA_SESSIONS_READ("okta.sessions.read", "Allows the app to read all sessions in your Okta organization", false), | ||
OKTA_TEMPLATES_MANAGE("okta.templates.manage", "Allows the app to manage all custom templates in your Okta organization", false), | ||
OKTA_TEMPLATES_READ("okta.templates.read", "Allows the app to read all custom templates in your Okta organization", false), | ||
OKTA_TRUSTEDORIGINS_MANAGE("okta.trustedOrigins.manage", "Allows the app to manage all Trusted Origins in your Okta organization", false), | ||
OKTA_TRUSTEDORIGINS_READ("okta.trustedOrigins.read", "Allows the app to read all Trusted Origins in your Okta organization", false), | ||
OKTA_POLICIES_MANAGE("okta.policies.manage", "Allows the app to manage Policies in your Okta organization", false), | ||
OKTA_POLICIES_READ("okta.policies.read", "Allows the app to read information about Policies in your Okta organization", false),; | ||
|
||
private final String scope; | ||
private final String description; | ||
private final boolean isDefault; | ||
|
||
} |
159 changes: 159 additions & 0 deletions
159
src/main/java/me/zhyd/oauth/request/AuthOktaRequest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
package me.zhyd.oauth.request; | ||
|
||
import com.alibaba.fastjson.JSONObject; | ||
import com.xkcoding.http.support.HttpHeader; | ||
import me.zhyd.oauth.cache.AuthStateCache; | ||
import me.zhyd.oauth.config.AuthConfig; | ||
import me.zhyd.oauth.config.AuthDefaultSource; | ||
import me.zhyd.oauth.enums.AuthResponseStatus; | ||
import me.zhyd.oauth.enums.AuthUserGender; | ||
import me.zhyd.oauth.enums.scope.AuthOktaScope; | ||
import me.zhyd.oauth.exception.AuthException; | ||
import me.zhyd.oauth.model.AuthCallback; | ||
import me.zhyd.oauth.model.AuthResponse; | ||
import me.zhyd.oauth.model.AuthToken; | ||
import me.zhyd.oauth.model.AuthUser; | ||
import me.zhyd.oauth.utils.AuthScopeUtils; | ||
import me.zhyd.oauth.utils.Base64Utils; | ||
import me.zhyd.oauth.utils.HttpUtils; | ||
import me.zhyd.oauth.utils.UrlBuilder; | ||
|
||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
/** | ||
* Okta 登录 | ||
* <p> | ||
* https://{domainPrefix}.okta.com/oauth2/default/.well-known/oauth-authorization-server | ||
* | ||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com) | ||
* @since 1.16.0 | ||
*/ | ||
public class AuthOktaRequest extends AuthDefaultRequest { | ||
|
||
public AuthOktaRequest(AuthConfig config) { | ||
super(config, AuthDefaultSource.OKTA); | ||
} | ||
|
||
public AuthOktaRequest(AuthConfig config, AuthStateCache authStateCache) { | ||
super(config, AuthDefaultSource.OKTA, authStateCache); | ||
} | ||
|
||
@Override | ||
protected AuthToken getAccessToken(AuthCallback authCallback) { | ||
String tokenUrl = accessTokenUrl(authCallback.getCode()); | ||
return getAuthToken(tokenUrl); | ||
} | ||
|
||
private AuthToken getAuthToken(String tokenUrl) { | ||
HttpHeader header = new HttpHeader() | ||
.add("accept", "application/json") | ||
.add("content-type", "application/x-www-form-urlencoded") | ||
.add("Authorization", "Basic " + Base64Utils.encode(config.getClientId().concat(":").concat(config.getClientSecret()))); | ||
String response = new HttpUtils(config.getHttpConfig()).post(tokenUrl, null, header, false); | ||
JSONObject accessTokenObject = JSONObject.parseObject(response); | ||
this.checkResponse(accessTokenObject); | ||
return AuthToken.builder() | ||
.accessToken(accessTokenObject.getString("access_token")) | ||
.tokenType(accessTokenObject.getString("token_type")) | ||
.expireIn(accessTokenObject.getIntValue("expires_in")) | ||
.scope(accessTokenObject.getString("scope")) | ||
.refreshToken(accessTokenObject.getString("refresh_token")) | ||
.idToken(accessTokenObject.getString("id_token")) | ||
.build(); | ||
} | ||
|
||
@Override | ||
public AuthResponse refresh(AuthToken authToken) { | ||
if (null == authToken.getRefreshToken()) { | ||
return AuthResponse.builder() | ||
.code(AuthResponseStatus.ILLEGAL_TOKEN.getCode()) | ||
.msg(AuthResponseStatus.ILLEGAL_TOKEN.getMsg()) | ||
.build(); | ||
} | ||
String refreshUrl = refreshTokenUrl(authToken.getRefreshToken()); | ||
return AuthResponse.builder() | ||
.code(AuthResponseStatus.SUCCESS.getCode()) | ||
.data(this.getAuthToken(refreshUrl)) | ||
.build(); | ||
} | ||
|
||
@Override | ||
protected AuthUser getUserInfo(AuthToken authToken) { | ||
HttpHeader header = new HttpHeader() | ||
.add("Authorization", "Bearer " + authToken.getAccessToken()); | ||
String response = new HttpUtils(config.getHttpConfig()).post(userInfoUrl(authToken), null, header, false); | ||
JSONObject object = JSONObject.parseObject(response); | ||
this.checkResponse(object); | ||
JSONObject address = object.getJSONObject("address"); | ||
return AuthUser.builder() | ||
.rawUserInfo(object) | ||
.uuid(object.getString("sub")) | ||
.username(object.getString("name")) | ||
.nickname(object.getString("nickname")) | ||
.email(object.getString("email")) | ||
.location(null == address ? null : address.getString("street_address")) | ||
.gender(AuthUserGender.getRealGender(object.getString("sex"))) | ||
.token(authToken) | ||
.source(source.toString()) | ||
.build(); | ||
} | ||
|
||
@Override | ||
public AuthResponse revoke(AuthToken authToken) { | ||
Map<String, String> params = new HashMap<>(4); | ||
params.put("token", authToken.getAccessToken()); | ||
params.put("token_type_hint", "access_token"); | ||
|
||
HttpHeader header = new HttpHeader() | ||
.add("Authorization", "Basic " + Base64Utils.encode(config.getClientId().concat(":").concat(config.getClientSecret()))); | ||
new HttpUtils(config.getHttpConfig()).post(revokeUrl(authToken), params, header, false); | ||
AuthResponseStatus status = AuthResponseStatus.SUCCESS; | ||
return AuthResponse.builder().code(status.getCode()).msg(status.getMsg()).build(); | ||
} | ||
|
||
private void checkResponse(JSONObject object) { | ||
if (object.containsKey("error")) { | ||
throw new AuthException(object.getString("error_description")); | ||
} | ||
} | ||
|
||
@Override | ||
public String authorize(String state) { | ||
return UrlBuilder.fromBaseUrl(String.format(source.authorize(), config.getDomainPrefix(), config.getAuthServerId())) | ||
.queryParam("response_type", "code") | ||
.queryParam("prompt", "consent") | ||
.queryParam("client_id", config.getClientId()) | ||
.queryParam("redirect_uri", config.getRedirectUri()) | ||
.queryParam("scope", this.getScopes(" ", true, AuthScopeUtils.getDefaultScopes(AuthOktaScope.values()))) | ||
.queryParam("state", getRealState(state)) | ||
.build(); | ||
} | ||
|
||
@Override | ||
public String accessTokenUrl(String code) { | ||
return UrlBuilder.fromBaseUrl(String.format(source.accessToken(), config.getDomainPrefix(), config.getAuthServerId())) | ||
.queryParam("code", code) | ||
.queryParam("grant_type", "authorization_code") | ||
.queryParam("redirect_uri", config.getRedirectUri()) | ||
.build(); | ||
} | ||
|
||
@Override | ||
protected String refreshTokenUrl(String refreshToken) { | ||
return UrlBuilder.fromBaseUrl(String.format(source.refresh(), config.getDomainPrefix(), config.getAuthServerId())) | ||
.queryParam("refresh_token", refreshToken) | ||
.queryParam("grant_type", "refresh_token") | ||
.build(); | ||
} | ||
|
||
@Override | ||
protected String revokeUrl(AuthToken authToken) { | ||
return String.format(source.revoke(), config.getDomainPrefix(), config.getAuthServerId()); | ||
} | ||
|
||
@Override | ||
public String userInfoUrl(AuthToken authToken) { | ||
return String.format(source.userInfo(), config.getDomainPrefix(), config.getAuthServerId()); | ||
} | ||
} |