提交 7a9e6214 编写于 作者: 智布道's avatar 智布道 👁

👽 集成 Okta

上级 3753e3b9
......@@ -7,8 +7,10 @@
- 集成 Amazon 平台登录
- 集成 Slack 平台登录
- 集成 LINE 平台登录
- 集成 Okta 平台登录
- 集成钉钉账号登录
- 修改
-**重要**`AuthConfig`中的`codingGroupName`参数更名为`domainPrefix`,针对此类平台提供通用的配置。
- 修改 `AuthFacebookScope` 中的默认 scope,解决 justauth-demo 项目中使用 facebook 报错的问题
- 升级 facebook 的 api 到 v10.0 版本
- 优化部分代码
......
......@@ -942,5 +942,38 @@ public enum AuthDefaultSource implements AuthSource {
public String revoke() {
return "https://api.line.me/oauth2/v2.1/revoke";
}
}
},
/**
* Okta,
* <p>
* 团队/组织的域名不同,此处通过配置动态组装
*
* @since 1.16.0
*/
OKTA {
@Override
public String authorize() {
return "https://%s.okta.com/oauth2/%s/v1/authorize";
}
@Override
public String accessToken() {
return "https://%s.okta.com/oauth2/%s/v1/token";
}
@Override
public String refresh() {
return "https://%s.okta.com/oauth2/%s/v1/token";
}
@Override
public String userInfo() {
return "https://%s.okta.com/oauth2/%s/v1/userinfo";
}
@Override
public String revoke() {
return "https://%s.okta.com/oauth2/%s/v1/revoke";
}
},
}
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;
}
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());
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册