mirror of
https://gitee.com/fujieid/jap.git
synced 2024-11-29 18:17:34 +08:00
Merge branch 'dev'
# Conflicts: # pom.xml
This commit is contained in:
commit
85aaec76ed
@ -1,6 +1,6 @@
|
||||
> 为了更高效率的处理 issue、解决问题,请按照如下格式填写 BUG 详情。
|
||||
>
|
||||
> 如果提交的 issue 不属于 BUG,可以忽略该问题模板。
|
||||
> 如果提交的 issue 不属于 BUG 范围,可以忽略/重置该问题模板。
|
||||
|
||||
## 提交前请确认:
|
||||
|
||||
@ -9,8 +9,16 @@
|
||||
|
||||
## 当前环境
|
||||
|
||||
- 使用的版本号(比如 `1.0.1`):
|
||||
- 出问题的模块(比如 `jap-ids`):
|
||||
- 出问题的模块:
|
||||
- [ ] jap-ids
|
||||
- [ ] jap-mfa
|
||||
- [ ] jap-oauth2
|
||||
- [ ] jap-oidc
|
||||
- [ ] jap-simple
|
||||
- [ ] jap-social
|
||||
- [ ] jap-sso
|
||||
- [ ] jap-core
|
||||
- 使用的 jap 版本号:
|
||||
|
||||
## 问题描述
|
||||
|
||||
@ -22,7 +30,7 @@
|
||||
|
||||
## 实际结果如何? 报错信息(请提交完整的截图或者日志)
|
||||
|
||||
> 一定要提供完整详细的异常堆栈。
|
||||
> 如果涉及到 BUG,请一定要提供完整详细的异常堆栈。
|
||||
|
||||
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
> - 是否新增了第三方依赖库?如果新增了第三方依赖库,其 LICENSE 是否兼容 LGPL-3.0? (LICENSE 兼容,请参考:[开源许可证兼容性指南 - 使用库的兼容性列表](https://shimo.im/docs/uL4VQaYGL2sadQOV#anchor-74ae))
|
||||
> - 是否参考/借鉴/复制了其他开源项目的代码?被引用的代码所属项目的 LICENSE 是否兼容 LGPL-3.0?(LICENSE 兼容,请参考:[开源许可证兼容性指南 - 合并/修改代码的许可证兼容性列表](https://shimo.im/docs/uL4VQaYGL2sadQOV#anchor-39f8))
|
||||
>
|
||||
> 如果你的代码或者代码中新引入的依赖项与 LGPL-3.0 不兼容,非常抱歉,我们可能不会合并你的代码。
|
||||
> 如果你的代码或者代码中新引入的依赖项与 LGPL-3.0 不兼容,非常抱歉,我们可能不会通过你的代码。
|
||||
>
|
||||
> 最后,感谢你的关注、支持。
|
||||
|
||||
@ -13,6 +13,9 @@
|
||||
|
||||
## 【必填】是否自测完成并提供了相关单元测试代码?
|
||||
|
||||
- [ ] 是,已经自测完成,并提供了单元测试代码,可以直接合并。
|
||||
- [ ] 否,仅完成了代码,并没做测试,也没有添加单元测试。
|
||||
|
||||
|
||||
## 【可选】关联的 Issue(有则填)
|
||||
|
||||
|
10
.github/ISSUE_TEMPLATE/bug_report.md
vendored
10
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -15,8 +15,16 @@ assignees: ''
|
||||
|
||||
## Environment
|
||||
|
||||
- JustAuthPlus(JAP) Module:
|
||||
- [ ] jap-ids
|
||||
- [ ] jap-mfa
|
||||
- [ ] jap-oauth2
|
||||
- [ ] jap-oidc
|
||||
- [ ] jap-simple
|
||||
- [ ] jap-social
|
||||
- [ ] jap-sso
|
||||
- [ ] jap-core
|
||||
- JustAuthPlus(JAP) version(e.g. `1.0.1`):
|
||||
- JustAuthPlus(JAP) Module(e.g. `jap-ids`):
|
||||
|
||||
### Minimal test code / Steps to reproduce the issue
|
||||
1.
|
||||
|
12
.github/ISSUE_TEMPLATE/request-help.md
vendored
12
.github/ISSUE_TEMPLATE/request-help.md
vendored
@ -12,5 +12,13 @@ assignees: ''
|
||||
|
||||
## Environment
|
||||
|
||||
- JustAuthPlus(JAP) version(e.g. `1.0.1`):
|
||||
- JustAuthPlus(JAP) Module(e.g. `jap-ids`):
|
||||
- JustAuthPlus(JAP) Module:
|
||||
- [ ] jap-ids
|
||||
- [ ] jap-mfa
|
||||
- [ ] jap-oauth2
|
||||
- [ ] jap-oidc
|
||||
- [ ] jap-simple
|
||||
- [ ] jap-social
|
||||
- [ ] jap-sso
|
||||
- [ ] jap-core
|
||||
- JustAuthPlus(JAP) version(e.g. `1.0.1`):
|
23
.github/workflows/publish-snapshot.yml
vendored
23
.github/workflows/publish-snapshot.yml
vendored
@ -7,8 +7,14 @@ on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [ dev ]
|
||||
paths:
|
||||
- src/**
|
||||
- pom.xml
|
||||
pull_request:
|
||||
branches: [ dev ]
|
||||
paths:
|
||||
- src/**
|
||||
- pom.xml
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
@ -30,7 +36,22 @@ jobs:
|
||||
gpg-passphrase: MAVEN_GPG_PASSWORD
|
||||
gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }}
|
||||
|
||||
- name: Publish to the Maven Central Repository
|
||||
- name: Cache m2 package
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.m2/repository
|
||||
key: ${{ runner.os }}-maven-${{ hashFiles('pom.xml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-maven-
|
||||
|
||||
- name: get current project version to set env.VERSION
|
||||
run: echo "VERSION=`mvn help:evaluate -Dexpression=project.version -q -DforceStdout`" >> $GITHUB_ENV
|
||||
|
||||
- name: set snapshot version
|
||||
if: ${{ !endsWith( env.VERSION , '-SNAPSHOT') }}
|
||||
run: mvn versions:set -DnewVersion=${{ env.VERSION }}-SNAPSHOT
|
||||
|
||||
- name: deploy snapshot to oss repository
|
||||
run: mvn clean deploy -P release
|
||||
env:
|
||||
MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }}
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -51,7 +51,6 @@ build/
|
||||
.vscode/
|
||||
|
||||
### other ###
|
||||
/jap-simple/src/main/java/com/fujieid/jap/simple/SimpleCallback.java
|
||||
/docs/bin/deploy.sh
|
||||
/jap-core/pom.xml.versionsBackup
|
||||
/jap-oauth2/pom.xml.versionsBackup
|
||||
|
@ -1,4 +1,87 @@
|
||||
## v1.0.4 (2021-08-**)
|
||||
## v1.0.5 (2021-09-15)
|
||||
|
||||
- feat: Add `jap-http-api` module. (Gitee Issue [#I43ZS7](https://gitee.com/fujieid/jap/issues/I43ZS7))
|
||||
- feat: Add `jap-ids-web` module. Package the filter of ids as a separate component.
|
||||
- feat: add HTTP servlet adapter to decouple jakarta servlets. **Note [1]**
|
||||
- feat: [jap-social] Support to bind the account of the third-party platform. (Gitee Issue [#I46J6W](https://gitee.com/fujieid/jap/issues/I46J6W))
|
||||
- change: [jap-ids] scope changed to optional.
|
||||
- change: [jap-sso] Upgrade `kisso` to 3.7.7, **Solve the vulnerability of jackson**.
|
||||
- change: [jap-mfa] Upgrade `googleauth` to 1.5.0, **Solve the vulnerability of apache httpclient**.
|
||||
- change: Upgrade `simple-http` to 1.0.5.
|
||||
- change: Upgrade `JustAuth` to 1.16.4.
|
||||
- change: Optimize code.
|
||||
|
||||
**Note [1]:**
|
||||
|
||||
In versions prior to version 1.0.5 of jap, rely on the `HttpServletRequest`, `Cookie`, `HttpServletResponse`, and `HttpSession` under the `javax.servlet.http` package in `jakarta-servlet`, such as:
|
||||
|
||||
```java
|
||||
// Interface provided by jap
|
||||
public interface JapStrategy {
|
||||
default JapResponse authenticate(AuthenticateConfig config, HttpServletRequest request, HttpServletResponse response) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```java
|
||||
// Use jap in spring framework
|
||||
XxJapStrategy.authenticate(config, request, response);
|
||||
```
|
||||
|
||||
In order to improve the adaptability of the framework, since version 1.0.5, JAP removed the dependency of `jakarta-servlet` and adopted a new set of interfaces (reference: [jap-http](https:gitee.comfujieidjap-http) ).
|
||||
|
||||
The developer needs to adapt the original request when calling the JAP interface.
|
||||
|
||||
For example, if the developer uses `jakarta-servlet`, then the `HttpServletRequest` needs to be adapted:
|
||||
|
||||
```java
|
||||
// Use 1.0.5 or higher version of jap in spring framework
|
||||
XxJapStrategy.authenticate(config, new JakartaRequestAdapter(request), new JakartaResponseAdapter(response));
|
||||
```
|
||||
|
||||
----
|
||||
|
||||
- feat: 增加 `jap-http-api` 模块。 (Gitee Issue [#I43ZS7](https://gitee.com/fujieid/jap/issues/I43ZS7))
|
||||
- feat: 增加 `jap-ids-web` 模块。 将 `jap-ids` 的过滤器打包为一个单独的组件。
|
||||
- feat: 添加 HTTP servlet 适配器以解耦 jakarta servlet。**注[1]**
|
||||
- feat: [jap-social] 支持绑定第三方平台账号,该版本将社会化登录和绑定账号独立开来,以使其更加使用与多场景。 (Gitee Issue [#I46J6W](https://gitee.com/fujieid/jap/issues/I46J6W))
|
||||
- change: [jap-ids] `scope` 在各个流程中都更改为可选,遵循 RFC6749 规范。
|
||||
- change: [jap-sso] 升级 `kisso` 的版本为 3.7.7, **解决 jackson 的漏洞**。
|
||||
- change: [jap-mfa] 升级 `googleauth` 的版本为 1.5.0, **解决 apache httpclient 的漏洞**。
|
||||
- change: 升级 `simple-http` 的版本为 1.0.5.
|
||||
- change: 升级 `JustAuth` 的版本为 1.16.4.
|
||||
- change: 优化代码。
|
||||
|
||||
**注[1]:**
|
||||
|
||||
在 1.0.5 以前版本,jap 中依赖 `jakarta-servlet` 中 `javax.servlet.http` 包下的 `HttpServletRequest`、`Cookie`、`HttpServletResponse`、`HttpSession`,比如:
|
||||
|
||||
```java
|
||||
// jap 提供的接口
|
||||
public interface JapStrategy {
|
||||
default JapResponse authenticate(AuthenticateConfig config, HttpServletRequest request, HttpServletResponse response) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```java
|
||||
// 在spring框架中使用 jap
|
||||
XxJapStrategy.authenticate(config, request, response);
|
||||
```
|
||||
|
||||
为了提高框架适配性,自 1.0.5 版本开始,JAP 去掉了 `jakarta-servlet` 依赖,采用了一套全新的接口(参考:[jap-http](https://gitee.com/fujieid/jap-http)),开发者在调用 JAP 接口时需要对原 request 进行适配。
|
||||
|
||||
比如,开发者使用了 `jakarta-servlet`,那么需要对 `HttpServletRequest` 进行适配处理:
|
||||
|
||||
```java
|
||||
// 在spring框架中使用 1.0.5 或更高级版本的 jap
|
||||
XxJapStrategy.authenticate(config, new JakartaRequestAdapter(request), new JakartaResponseAdapter(response));
|
||||
```
|
||||
|
||||
|
||||
## v1.0.4 (2021-08-15)
|
||||
|
||||
- fix: [jap-ids] Support to generate custom token. (Gitee[#I3U1ON](https://gitee.com/fujieid/jap/issues/I3U1ON))
|
||||
- fix: [jap-ids] Support custom verification of client_secret, such as: BCrypt, etc. (Gitee[#I44032](https://gitee.com/fujieid/jap/issues/I44032))
|
||||
@ -10,6 +93,7 @@
|
||||
- doc: change the template of issue and PR
|
||||
|
||||
----
|
||||
|
||||
- fix: [jap-ids] 支持生成自定义 token(包含 access_token 和 refresh_token)。 (Gitee[#I3U1ON](https://gitee.com/fujieid/jap/issues/I3U1ON))
|
||||
- fix: [jap-ids] 支持自定义验证 `client_secret`,适配多种场景,如:BCrypt 等。 (Gitee[#I44032](https://gitee.com/fujieid/jap/issues/I44032))
|
||||
- feat: [jap-ids] 当启用 `IdsConfig#enableDynamicIssuer` 时,支持自定义 `context-path`
|
||||
|
@ -86,6 +86,18 @@ public interface JapUserService {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* After logging in, bind the account of the third-party platform
|
||||
*
|
||||
* @param japUser User information of the third-party platform after successful login
|
||||
* @param bindUserId The user id that needs to be bound, this is a user of the business system, not a user of the third-party platform.
|
||||
* @return When binding successfully, return {@code true}, otherwise return {@code false}
|
||||
*/
|
||||
default boolean bindSocialUser(JapUser japUser, String bindUserId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the oauth login user information to the database and return JapUser
|
||||
* <p>
|
||||
@ -101,4 +113,15 @@ public interface JapUserService {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the http authed user information to the database and return JapUser
|
||||
* <p>
|
||||
* It is suitable for the {@code jap-http-api} module
|
||||
* @param userinfo user information
|
||||
* @return When saving successfully, return {@code JapUser}, otherwise return {@code null}
|
||||
*/
|
||||
default JapUser createAndGetHttpApiUser(Object userinfo){
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
26
jap-core/src/main/java/com/fujieid/jap/core/cache/package-info.java
vendored
Normal file
26
jap-core/src/main/java/com/fujieid/jap/core/cache/package-info.java
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/**
|
||||
* The cache component of jap has a built-in local cache based on MAP.
|
||||
* <p>
|
||||
* Developers can implement specific cache solutions based on the {@link com.fujieid.jap.core.cache.JapCache} interface,
|
||||
* such as redis cache.
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
package com.fujieid.jap.core.cache;
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/**
|
||||
* JAP configuration file, including common configuration and common configuration classes.
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
package com.fujieid.jap.core.config;
|
@ -25,12 +25,12 @@ import com.fujieid.jap.core.result.JapErrorCode;
|
||||
import com.fujieid.jap.core.result.JapResponse;
|
||||
import com.fujieid.jap.core.store.JapUserStore;
|
||||
import com.fujieid.jap.core.util.JapTokenHelper;
|
||||
import com.fujieid.jap.core.util.RequestUtil;
|
||||
import com.fujieid.jap.http.JapHttpCookie;
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.http.JapHttpResponse;
|
||||
import com.fujieid.jap.http.RequestUtil;
|
||||
import com.xkcoding.json.util.Kv;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
@ -74,7 +74,7 @@ public class JapAuthentication implements Serializable {
|
||||
* @param response current HTTP response
|
||||
* @return JapUser
|
||||
*/
|
||||
public static JapUser getUser(HttpServletRequest request, HttpServletResponse response) {
|
||||
public static JapUser getUser(JapHttpRequest request, JapHttpResponse response) {
|
||||
if (null == context) {
|
||||
return null;
|
||||
}
|
||||
@ -107,7 +107,7 @@ public class JapAuthentication implements Serializable {
|
||||
* @param response current HTTP response
|
||||
* @return JapResponse
|
||||
*/
|
||||
public static JapResponse checkUser(HttpServletRequest request, HttpServletResponse response) {
|
||||
public static JapResponse checkUser(JapHttpRequest request, JapHttpResponse response) {
|
||||
JapUser japUser = getUser(request, response);
|
||||
if (null == japUser) {
|
||||
return JapResponse.error(JapErrorCode.NOT_LOGGED_IN);
|
||||
@ -154,7 +154,7 @@ public class JapAuthentication implements Serializable {
|
||||
* @param response current HTTP response
|
||||
* @return boolean
|
||||
*/
|
||||
public static boolean logout(HttpServletRequest request, HttpServletResponse response) {
|
||||
public static boolean logout(JapHttpRequest request, JapHttpResponse response) {
|
||||
JapUserStore japUserStore = context.getUserStore();
|
||||
if (null == japUserStore) {
|
||||
return false;
|
||||
@ -162,7 +162,7 @@ public class JapAuthentication implements Serializable {
|
||||
japUserStore.remove(request, response);
|
||||
|
||||
// Clear all cookie information
|
||||
Map<String, Cookie> cookieMap = RequestUtil.getCookieMap(request);
|
||||
Map<String, JapHttpCookie> cookieMap = RequestUtil.getCookieMap(request);
|
||||
if (CollectionUtil.isNotEmpty(cookieMap)) {
|
||||
cookieMap.forEach((key, cookie) -> {
|
||||
cookie.setMaxAge(0);
|
||||
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/**
|
||||
* JAP context
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
package com.fujieid.jap.core.context;
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
/**
|
||||
* Jap core module, external specification interface standard
|
||||
* Jap core module, Provide external standard interface support
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0.0
|
||||
|
@ -38,6 +38,7 @@ public enum JapErrorCode {
|
||||
MISS_ISSUER(1006, "OidcStrategy requires a issuer option."),
|
||||
MISS_CREDENTIALS(1007, "Missing credentials"),
|
||||
INVALID_GRANT_TYPE(1008, "The grant type is not supported by the authorization server, or the current client is not authorized for the grant type."),
|
||||
ERROR_HTTP_API_CONFIG(1008,"http api config error,please check")
|
||||
;
|
||||
|
||||
private final int errroCode;
|
||||
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/**
|
||||
* Used to standardize the return value and exception status code of the JAP interface.
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
package com.fujieid.jap.core.result;
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/**
|
||||
* Supports SPI features. When implementing an interface, developers can pass parameters through the <code>setXx</code> method,
|
||||
* or through the SPI specification. for example:
|
||||
* <p>
|
||||
* For the <code>JapUserService</code> interface provided by jap, developers can set the interface implementation class through <code>xx.setUserService</code>,
|
||||
* You can also configure the implementation class of the interface in a file named after the interface name in the <code>resources/META-INF/services</code> folder, such as:
|
||||
* <code>resources/META-INF/services/com.fujieid.jap.core.JapUserService</code>, the content of the file is <code>xx.xxx.xx.JapUserServiceImpl</code>
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
package com.fujieid.jap.core.spi;
|
@ -16,9 +16,8 @@
|
||||
package com.fujieid.jap.core.store;
|
||||
|
||||
import com.fujieid.jap.core.JapUser;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.http.JapHttpResponse;
|
||||
|
||||
/**
|
||||
* Save, delete and obtain the login user information.By default, based on local caching,
|
||||
@ -38,7 +37,7 @@ public interface JapUserStore {
|
||||
* @param japUser User information after successful login
|
||||
* @return JapUser
|
||||
*/
|
||||
JapUser save(HttpServletRequest request, HttpServletResponse response, JapUser japUser);
|
||||
JapUser save(JapHttpRequest request, JapHttpResponse response, JapUser japUser);
|
||||
|
||||
/**
|
||||
* Clear user information from cache
|
||||
@ -46,7 +45,7 @@ public interface JapUserStore {
|
||||
* @param request current HTTP request
|
||||
* @param response current HTTP response
|
||||
*/
|
||||
void remove(HttpServletRequest request, HttpServletResponse response);
|
||||
void remove(JapHttpRequest request, JapHttpResponse response);
|
||||
|
||||
/**
|
||||
* Get the login user information from the cache, return {@code JapUser} if it exists,
|
||||
@ -56,5 +55,5 @@ public interface JapUserStore {
|
||||
* @param response current HTTP response
|
||||
* @return JapUser
|
||||
*/
|
||||
JapUser get(HttpServletRequest request, HttpServletResponse response);
|
||||
JapUser get(JapHttpRequest request, JapHttpResponse response);
|
||||
}
|
||||
|
@ -22,10 +22,9 @@ import com.fujieid.jap.core.config.JapConfig;
|
||||
import com.fujieid.jap.core.context.JapAuthentication;
|
||||
import com.fujieid.jap.core.util.JapTokenHelper;
|
||||
import com.fujieid.jap.core.util.JapUtil;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.http.JapHttpResponse;
|
||||
import com.fujieid.jap.http.JapHttpSession;
|
||||
|
||||
/**
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
@ -46,8 +45,8 @@ public class SessionJapUserStore implements JapUserStore {
|
||||
* @return JapUser
|
||||
*/
|
||||
@Override
|
||||
public JapUser save(HttpServletRequest request, HttpServletResponse response, JapUser japUser) {
|
||||
HttpSession session = request.getSession();
|
||||
public JapUser save(JapHttpRequest request, JapHttpResponse response, JapUser japUser) {
|
||||
JapHttpSession session = request.getSession();
|
||||
JapUser newUser = BeanUtil.copyProperties(japUser, JapUser.class);
|
||||
newUser.setPassword(null);
|
||||
session.setAttribute(JapConst.SESSION_USER_KEY, newUser);
|
||||
@ -68,7 +67,7 @@ public class SessionJapUserStore implements JapUserStore {
|
||||
* @param response current HTTP response
|
||||
*/
|
||||
@Override
|
||||
public void remove(HttpServletRequest request, HttpServletResponse response) {
|
||||
public void remove(JapHttpRequest request, JapHttpResponse response) {
|
||||
|
||||
JapConfig japConfig = JapAuthentication.getContext().getConfig();
|
||||
if (!japConfig.isSso()) {
|
||||
@ -78,7 +77,7 @@ public class SessionJapUserStore implements JapUserStore {
|
||||
}
|
||||
}
|
||||
|
||||
HttpSession session = request.getSession();
|
||||
JapHttpSession session = request.getSession();
|
||||
session.removeAttribute(JapConst.SESSION_USER_KEY);
|
||||
session.invalidate();
|
||||
}
|
||||
@ -92,8 +91,8 @@ public class SessionJapUserStore implements JapUserStore {
|
||||
* @return JapUser
|
||||
*/
|
||||
@Override
|
||||
public JapUser get(HttpServletRequest request, HttpServletResponse response) {
|
||||
HttpSession session = request.getSession();
|
||||
public JapUser get(JapHttpRequest request, JapHttpResponse response) {
|
||||
JapHttpSession session = request.getSession();
|
||||
return (JapUser) session.getAttribute(JapConst.SESSION_USER_KEY);
|
||||
}
|
||||
}
|
||||
|
@ -19,12 +19,11 @@ import cn.hutool.core.util.StrUtil;
|
||||
import com.fujieid.jap.core.JapUser;
|
||||
import com.fujieid.jap.core.JapUserService;
|
||||
import com.fujieid.jap.core.util.JapTokenHelper;
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.http.JapHttpResponse;
|
||||
import com.fujieid.jap.sso.JapSsoHelper;
|
||||
import com.fujieid.jap.sso.config.JapSsoConfig;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* Operation on users in SSO mode (cookie)
|
||||
*
|
||||
@ -57,7 +56,7 @@ public class SsoJapUserStore extends SessionJapUserStore {
|
||||
* @return JapUser
|
||||
*/
|
||||
@Override
|
||||
public JapUser save(HttpServletRequest request, HttpServletResponse response, JapUser japUser) {
|
||||
public JapUser save(JapHttpRequest request, JapHttpResponse response, JapUser japUser) {
|
||||
String token = JapSsoHelper.login(japUser.getUserId(), japUser.getUsername(), this.japSsoConfig, request, response);
|
||||
super.save(request, response, japUser);
|
||||
JapTokenHelper.saveUserToken(japUser.getUserId(), token);
|
||||
@ -71,7 +70,7 @@ public class SsoJapUserStore extends SessionJapUserStore {
|
||||
* @param response current HTTP response
|
||||
*/
|
||||
@Override
|
||||
public void remove(HttpServletRequest request, HttpServletResponse response) {
|
||||
public void remove(JapHttpRequest request, JapHttpResponse response) {
|
||||
JapUser japUser = this.get(request, response);
|
||||
if (null != japUser) {
|
||||
JapTokenHelper.removeUserToken(japUser.getUserId());
|
||||
@ -89,7 +88,7 @@ public class SsoJapUserStore extends SessionJapUserStore {
|
||||
* @return JapUser
|
||||
*/
|
||||
@Override
|
||||
public JapUser get(HttpServletRequest request, HttpServletResponse response) {
|
||||
public JapUser get(JapHttpRequest request, JapHttpResponse response) {
|
||||
String userId = JapSsoHelper.checkLogin(request);
|
||||
if (StrUtil.isBlank(userId)) {
|
||||
// The cookie has expired. Clear session content
|
||||
|
@ -32,11 +32,10 @@ import com.fujieid.jap.core.result.JapResponse;
|
||||
import com.fujieid.jap.core.store.JapUserStore;
|
||||
import com.fujieid.jap.core.store.SessionJapUserStore;
|
||||
import com.fujieid.jap.core.store.SsoJapUserStore;
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.http.JapHttpResponse;
|
||||
import com.fujieid.jap.sso.JapSsoHelper;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* General policy handling methods and parameters, policies of other platforms can inherit
|
||||
* {@code AbstractJapStrategy}, and override the constructor
|
||||
@ -106,11 +105,11 @@ public abstract class AbstractJapStrategy implements JapStrategy {
|
||||
* @param response current HTTP response
|
||||
* @return boolean
|
||||
*/
|
||||
protected JapUser checkSession(HttpServletRequest request, HttpServletResponse response) {
|
||||
protected JapUser checkSession(JapHttpRequest request, JapHttpResponse response) {
|
||||
return japContext.getUserStore().get(request, response);
|
||||
}
|
||||
|
||||
protected JapResponse loginSuccess(JapUser japUser, HttpServletRequest request, HttpServletResponse response) {
|
||||
protected JapResponse loginSuccess(JapUser japUser, JapHttpRequest request, JapHttpResponse response) {
|
||||
japContext.getUserStore().save(request, response, japUser);
|
||||
return JapResponse.success(japUser);
|
||||
}
|
||||
|
@ -18,9 +18,8 @@ package com.fujieid.jap.core.strategy;
|
||||
import com.fujieid.jap.core.config.AuthenticateConfig;
|
||||
import com.fujieid.jap.core.result.JapErrorCode;
|
||||
import com.fujieid.jap.core.result.JapResponse;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.http.JapHttpResponse;
|
||||
|
||||
/**
|
||||
* The unified implementation interface of JAP Strategy, which must be implemented for all specific business policies.
|
||||
@ -39,7 +38,7 @@ public interface JapStrategy {
|
||||
* @param response The response to authenticate
|
||||
* @return JapResponse
|
||||
*/
|
||||
default JapResponse authenticate(AuthenticateConfig config, HttpServletRequest request, HttpServletResponse response) {
|
||||
default JapResponse authenticate(AuthenticateConfig config, JapHttpRequest request, JapHttpResponse response) {
|
||||
return JapResponse.error(JapErrorCode.ERROR.getErrroCode(), "JapStrategy#authenticate(AuthenticateConfig, HttpServletRequest, HttpServletResponse) must be overridden by subclass");
|
||||
}
|
||||
}
|
||||
|
@ -16,13 +16,10 @@
|
||||
package com.fujieid.jap.core.util;
|
||||
|
||||
import com.fujieid.jap.core.JapUser;
|
||||
import com.fujieid.jap.core.exception.JapException;
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.http.JapHttpResponse;
|
||||
import com.fujieid.jap.sso.JapSsoUtil;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* The tool class of Jap only provides static methods common to all modules
|
||||
*
|
||||
@ -35,20 +32,16 @@ public class JapUtil extends com.xkcoding.json.util.ObjectUtil {
|
||||
private static final String REDIRECT_ERROR = "JAP failed to redirect via HttpServletResponse.";
|
||||
|
||||
@Deprecated
|
||||
public static void redirect(String url, HttpServletResponse response) {
|
||||
public static void redirect(String url, JapHttpResponse response) {
|
||||
redirect(url, REDIRECT_ERROR, response);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static void redirect(String url, String errorMessage, HttpServletResponse response) {
|
||||
try {
|
||||
response.sendRedirect(url);
|
||||
} catch (IOException ex) {
|
||||
throw new JapException(errorMessage, ex);
|
||||
}
|
||||
public static void redirect(String url, String errorMessage, JapHttpResponse response) {
|
||||
response.redirect(url);
|
||||
}
|
||||
|
||||
public static String createToken(JapUser japUser, HttpServletRequest request) {
|
||||
public static String createToken(JapUser japUser, JapHttpRequest request) {
|
||||
return JapSsoUtil.createToken(japUser.getUserId(), japUser.getUsername(), request);
|
||||
}
|
||||
}
|
||||
|
@ -1,246 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fujieid.jap.core.util;
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import com.xkcoding.json.util.StringUtil;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* http servlet request util
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0.0
|
||||
* @since 1.0.1
|
||||
*/
|
||||
public class RequestUtil {
|
||||
|
||||
/**
|
||||
* Get the url parameter value of the request through {@code request.getParameter(paramName)}
|
||||
*
|
||||
* @param paramName parameter name
|
||||
* @param request current HTTP request
|
||||
* @return string
|
||||
*/
|
||||
public static String getParam(String paramName, HttpServletRequest request) {
|
||||
if (null == request) {
|
||||
return null;
|
||||
}
|
||||
return request.getParameter(paramName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get request header
|
||||
*
|
||||
* @param headerName request header name
|
||||
* @param request current HTTP request
|
||||
* @return string
|
||||
*/
|
||||
public static String getHeader(String headerName, HttpServletRequest request) {
|
||||
if (null == request) {
|
||||
return "";
|
||||
}
|
||||
return request.getHeader(headerName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the referer of the current HTTP request
|
||||
*
|
||||
* @param request current HTTP request
|
||||
* @return string
|
||||
*/
|
||||
public static String getReferer(HttpServletRequest request) {
|
||||
return getHeader("Referer", request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get subdomain name
|
||||
*
|
||||
* @param request current HTTP request
|
||||
* @return string
|
||||
*/
|
||||
public static String getFullDomainName(HttpServletRequest request) {
|
||||
StringBuffer url = request.getRequestURL();
|
||||
return url.delete(url.length() - request.getRequestURI().length(), url.length()).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the User-Agent of the current HTTP request
|
||||
*
|
||||
* @param request current HTTP request
|
||||
* @return string
|
||||
*/
|
||||
public static String getUa(HttpServletRequest request) {
|
||||
return getHeader("User-Agent", request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the IP of the current HTTP request
|
||||
*
|
||||
* @param request current HTTP request
|
||||
* @return string
|
||||
*/
|
||||
public static String getIp(HttpServletRequest request) {
|
||||
if (null == request) {
|
||||
return "";
|
||||
}
|
||||
String[] headers = {"X-Forwarded-For", "X-Real-IP", "Proxy-Client-IP", "WL-Proxy-Client-IP", "HTTP_CLIENT_IP", "HTTP_X_FORWARDED_FOR"};
|
||||
String ip;
|
||||
for (String header : headers) {
|
||||
ip = request.getHeader(header);
|
||||
if (isValidIp(ip)) {
|
||||
return getMultistageReverseProxyIp(ip);
|
||||
}
|
||||
}
|
||||
ip = request.getRemoteAddr();
|
||||
return getMultistageReverseProxyIp(ip);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the first non-unknown ip address from the multi-level reverse proxy
|
||||
*
|
||||
* @param ip IP
|
||||
* @return The first non-unknown ip address
|
||||
*/
|
||||
private static String getMultistageReverseProxyIp(String ip) {
|
||||
if (ip != null && ip.indexOf(",") > 0) {
|
||||
final String[] ips = ip.trim().split(",");
|
||||
for (String subIp : ips) {
|
||||
if (isValidIp(subIp)) {
|
||||
ip = subIp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify ip legitimacy
|
||||
*
|
||||
* @param ip ip
|
||||
* @return boolean
|
||||
*/
|
||||
private static boolean isValidIp(String ip) {
|
||||
return !StringUtil.isEmpty(ip) && !"unknown".equalsIgnoreCase(ip);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the request url
|
||||
*
|
||||
* @param encode Whether to encode url
|
||||
* @param request current HTTP request
|
||||
* @return string
|
||||
*/
|
||||
public static String getRequestUrl(boolean encode, HttpServletRequest request) {
|
||||
if (null == request) {
|
||||
return "";
|
||||
}
|
||||
String currentUrl = request.getRequestURL().toString();
|
||||
String queryString = request.getQueryString();
|
||||
if (!StringUtil.isEmpty(queryString)) {
|
||||
currentUrl = currentUrl + "?" + queryString;
|
||||
}
|
||||
|
||||
if (encode) {
|
||||
String result = "";
|
||||
try {
|
||||
result = URLEncoder.encode(currentUrl, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
//ignore
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return currentUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the cookie
|
||||
*
|
||||
* @param request current HTTP request
|
||||
* @param name cookie name
|
||||
* @return String
|
||||
*/
|
||||
public static String getCookieVal(HttpServletRequest request, String name) {
|
||||
Cookie cookie = getCookie(request, name);
|
||||
return cookie != null ? cookie.getValue() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cookie
|
||||
*
|
||||
* @param request current HTTP request
|
||||
* @param name cookie name
|
||||
* @return Cookie
|
||||
*/
|
||||
public static Cookie getCookie(HttpServletRequest request, String name) {
|
||||
Cookie[] cookies = request.getCookies();
|
||||
if (cookies != null) {
|
||||
for (Cookie cookie : cookies) {
|
||||
if (name.equals(cookie.getName())) {
|
||||
return cookie;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the cookies, and use the cookie name as the key to form a map
|
||||
*
|
||||
* @param request current HTTP request
|
||||
* @return Map
|
||||
*/
|
||||
public static Map<String, Cookie> getCookieMap(HttpServletRequest request) {
|
||||
final Cookie[] cookies = request.getCookies();
|
||||
if (ArrayUtil.isEmpty(cookies)) {
|
||||
return MapUtil.empty();
|
||||
}
|
||||
|
||||
return Arrays.stream(cookies).collect(Collectors.toMap(Cookie::getName, v -> v, (k1, k2) -> k1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set cookie
|
||||
*
|
||||
* @param response current HTTP response
|
||||
* @param name cookie name
|
||||
* @param value cookie value
|
||||
* @param maxAge maxAge
|
||||
* @param path path
|
||||
* @param domain domain
|
||||
*/
|
||||
public static void setCookie(HttpServletResponse response, String name, String value, int maxAge, String path, String domain) {
|
||||
Cookie cookie = new Cookie(name, value);
|
||||
cookie.setPath(path);
|
||||
if (null != domain) {
|
||||
cookie.setDomain(domain);
|
||||
}
|
||||
cookie.setMaxAge(maxAge);
|
||||
cookie.setHttpOnly(false);
|
||||
response.addCookie(cookie);
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/**
|
||||
* jap general tools
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
package com.fujieid.jap.core.util;
|
@ -22,6 +22,10 @@ import com.fujieid.jap.core.cache.JapLocalCache;
|
||||
import com.fujieid.jap.core.config.JapConfig;
|
||||
import com.fujieid.jap.core.result.JapResponse;
|
||||
import com.fujieid.jap.core.store.JapUserStore;
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.http.JapHttpResponse;
|
||||
import com.fujieid.jap.http.jakarta.JakartaRequestAdapter;
|
||||
import com.fujieid.jap.http.jakarta.JakartaResponseAdapter;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@ -39,9 +43,14 @@ public class JapAuthenticationTest {
|
||||
@Mock
|
||||
public HttpServletResponse httpServletResponseMock;
|
||||
|
||||
public JapHttpRequest request;
|
||||
public JapHttpResponse response;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
this.request = new JakartaRequestAdapter(httpServletRequestMock);
|
||||
this.response = new JakartaResponseAdapter(httpServletResponseMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -71,7 +80,7 @@ public class JapAuthenticationTest {
|
||||
JapContext japContext = new JapContext(japUserStore, japCache, japConfig);
|
||||
JapAuthentication.setContext(japContext);
|
||||
|
||||
JapUser japUser = JapAuthentication.getContext().getUserStore().get(httpServletRequestMock, httpServletResponseMock);
|
||||
JapUser japUser = JapAuthentication.getContext().getUserStore().get(request, response);
|
||||
Assert.assertNull(japUser);
|
||||
}
|
||||
|
||||
@ -83,8 +92,8 @@ public class JapAuthenticationTest {
|
||||
JapContext japContext = new JapContext(japUserStore, japCache, japConfig);
|
||||
JapAuthentication.setContext(japContext);
|
||||
|
||||
JapAuthentication.getContext().getUserStore().save(httpServletRequestMock, httpServletResponseMock, new JapUser());
|
||||
JapUser japUser = JapAuthentication.getContext().getUserStore().get(httpServletRequestMock, httpServletResponseMock);
|
||||
JapAuthentication.getContext().getUserStore().save(request, response, new JapUser());
|
||||
JapUser japUser = JapAuthentication.getContext().getUserStore().get(request, response);
|
||||
Assert.assertNotNull(japUser);
|
||||
}
|
||||
|
||||
@ -96,7 +105,7 @@ public class JapAuthenticationTest {
|
||||
JapContext japContext = new JapContext(japUserStore, japCache, japConfig);
|
||||
JapAuthentication.setContext(japContext);
|
||||
|
||||
JapUser japUser = JapAuthentication.getUser(httpServletRequestMock, httpServletResponseMock);
|
||||
JapUser japUser = JapAuthentication.getUser(request, response);
|
||||
Assert.assertNull(japUser);
|
||||
}
|
||||
|
||||
@ -108,8 +117,8 @@ public class JapAuthenticationTest {
|
||||
JapContext japContext = new JapContext(japUserStore, japCache, japConfig);
|
||||
JapAuthentication.setContext(japContext);
|
||||
|
||||
JapResponse response = JapAuthentication.checkUser(httpServletRequestMock, httpServletResponseMock);
|
||||
Assert.assertEquals(response.getCode(), 401);
|
||||
JapResponse japResponse = JapAuthentication.checkUser(request, response);
|
||||
Assert.assertEquals(japResponse.getCode(), 401);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -120,9 +129,9 @@ public class JapAuthenticationTest {
|
||||
JapContext japContext = new JapContext(japUserStore, japCache, japConfig);
|
||||
JapAuthentication.setContext(japContext);
|
||||
|
||||
JapAuthentication.getContext().getUserStore().save(httpServletRequestMock, httpServletResponseMock, new JapUser());
|
||||
JapResponse response = JapAuthentication.checkUser(httpServletRequestMock, httpServletResponseMock);
|
||||
Assert.assertEquals(response.getCode(), 200);
|
||||
JapAuthentication.getContext().getUserStore().save(request, response, new JapUser());
|
||||
JapResponse japResponse = JapAuthentication.checkUser(request, response);
|
||||
Assert.assertEquals(japResponse.getCode(), 200);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -195,7 +204,7 @@ public class JapAuthenticationTest {
|
||||
JapContext japContext = new JapContext(japUserStore, japCache, japConfig);
|
||||
JapAuthentication.setContext(japContext);
|
||||
|
||||
boolean result = JapAuthentication.logout(httpServletRequestMock, httpServletResponseMock);
|
||||
boolean result = JapAuthentication.logout(request, response);
|
||||
Assert.assertTrue(result);
|
||||
}
|
||||
|
||||
@ -207,7 +216,7 @@ public class JapAuthenticationTest {
|
||||
JapContext japContext = new JapContext(japUserStore, japCache, japConfig);
|
||||
JapAuthentication.setContext(japContext);
|
||||
|
||||
boolean result = JapAuthentication.logout(httpServletRequestMock, httpServletResponseMock);
|
||||
boolean result = JapAuthentication.logout(request, response);
|
||||
Assert.assertFalse(result);
|
||||
}
|
||||
|
||||
@ -224,7 +233,7 @@ public class JapAuthenticationTest {
|
||||
* @return JapUser
|
||||
*/
|
||||
@Override
|
||||
public JapUser save(HttpServletRequest request, HttpServletResponse response, JapUser japUser) {
|
||||
public JapUser save(JapHttpRequest request, JapHttpResponse response, JapUser japUser) {
|
||||
STORE.put(USER_KEY, japUser);
|
||||
return japUser;
|
||||
}
|
||||
@ -236,7 +245,7 @@ public class JapAuthenticationTest {
|
||||
* @param response current HTTP response
|
||||
*/
|
||||
@Override
|
||||
public void remove(HttpServletRequest request, HttpServletResponse response) {
|
||||
public void remove(JapHttpRequest request, JapHttpResponse response) {
|
||||
STORE.remove(USER_KEY);
|
||||
}
|
||||
|
||||
@ -249,7 +258,7 @@ public class JapAuthenticationTest {
|
||||
* @return JapUser
|
||||
*/
|
||||
@Override
|
||||
public JapUser get(HttpServletRequest request, HttpServletResponse response) {
|
||||
public JapUser get(JapHttpRequest request, JapHttpResponse response) {
|
||||
return (JapUser) STORE.get(USER_KEY);
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,8 @@
|
||||
package com.fujieid.jap.core.util;
|
||||
|
||||
import com.fujieid.jap.core.JapUser;
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.http.jakarta.JakartaRequestAdapter;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@ -30,9 +32,12 @@ public class JapUtilTest {
|
||||
@Mock
|
||||
public HttpServletRequest httpServletRequestMock;
|
||||
|
||||
public JapHttpRequest request;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
this.request = new JakartaRequestAdapter(httpServletRequestMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -41,7 +46,7 @@ public class JapUtilTest {
|
||||
when(httpServletRequestMock.getHeader("user-agent")).thenReturn("ua");
|
||||
String token = JapUtil.createToken(new JapUser()
|
||||
.setUserId("11111")
|
||||
.setUsername("username"), httpServletRequestMock);
|
||||
.setUsername("username"), request);
|
||||
Assert.assertNotNull(token);
|
||||
}
|
||||
}
|
||||
|
29
jap-http-api/pom.xml
Normal file
29
jap-http-api/pom.xml
Normal file
@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>com.fujieid</groupId>
|
||||
<artifactId>jap</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>jap-http-api</artifactId>
|
||||
<name>jap-http-api</name>
|
||||
<description>
|
||||
jap-http-api
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.fujieid</groupId>
|
||||
<artifactId>jap-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.xkcoding.http</groupId>
|
||||
<artifactId>simple-http</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -0,0 +1,228 @@
|
||||
package com.fujieid.jap.httpapi;
|
||||
|
||||
import com.fujieid.jap.core.JapUser;
|
||||
import com.fujieid.jap.core.config.AuthenticateConfig;
|
||||
import com.fujieid.jap.httpapi.enums.AuthInfoFieldEnum;
|
||||
import com.fujieid.jap.httpapi.enums.AuthSchemaEnum;
|
||||
import com.fujieid.jap.httpapi.enums.ForBearerTokenEnum;
|
||||
import com.fujieid.jap.httpapi.enums.HttpMethodEnum;
|
||||
import com.fujieid.jap.httpapi.strategy.GetTokenFromResponseStrategy;
|
||||
import com.fujieid.jap.httpapi.strategy.RequestBodyToJapUserStrategy;
|
||||
import com.xkcoding.json.JsonUtil;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Configuration file for http api authorization module
|
||||
*
|
||||
* @author zhihai.yu (mvbbb(a)foxmail.com)
|
||||
* @version 1.0.0
|
||||
* @since 1.0.5
|
||||
*/
|
||||
public class HttpApiConfig extends AuthenticateConfig {
|
||||
|
||||
/**
|
||||
* Schema for http authorization,defined by third-party system. eg:BASIC、DIGEST、BEARER.
|
||||
*/
|
||||
private AuthSchemaEnum authSchema;
|
||||
|
||||
/**
|
||||
* the http method for us to send request to third-party system, which is given by third-party system.
|
||||
*/
|
||||
private HttpMethodEnum httpMethod;
|
||||
|
||||
/**
|
||||
* the login url given by the third-party system.
|
||||
*/
|
||||
private String loginUrl;
|
||||
|
||||
/**
|
||||
* params/header/body
|
||||
*/
|
||||
private AuthInfoFieldEnum authInfoField;
|
||||
|
||||
/**
|
||||
* custom headers will be carried when request third-party system.
|
||||
*/
|
||||
private Map<String, String> customHeaders;
|
||||
|
||||
/**
|
||||
* custom params will be carried when request third-party system.
|
||||
*/
|
||||
private Map<String, String> customParams;
|
||||
|
||||
/**
|
||||
* custom body will be carried when request third-party system in json format.
|
||||
*/
|
||||
private Map<String, String> customBody;
|
||||
|
||||
/**
|
||||
* define this field when authSchema is BEARER
|
||||
*/
|
||||
private String bearerTokenIssueUrl;
|
||||
|
||||
/**
|
||||
* if user auth info field is "body", by default, analyze user auth info by json format. ex:
|
||||
* {
|
||||
* "username":"admin",
|
||||
* "password":"123456"
|
||||
* }
|
||||
* Developer's system should customize requestBodyToJapUserStrategy to get userinfo form request if user auth info is not this format.
|
||||
*/
|
||||
private RequestBodyToJapUserStrategy requestBodyToJapUserStrategy = request -> {
|
||||
BufferedReader reader = request.getReader();
|
||||
StringBuilder body = new StringBuilder();
|
||||
String str = null;
|
||||
while ((str = reader.readLine()) != null) {
|
||||
body.append(str);
|
||||
}
|
||||
return JsonUtil.toBean(body.toString(), JapUser.class);
|
||||
};
|
||||
|
||||
/**
|
||||
* As we know Bearer auth need a token, but how to get this token? we should do a pre-auth to get this token, then store this token
|
||||
* in developer's system. when user request for bearer auth, http-api module will query for user's token in our system.
|
||||
* This field is used to define how to do pre-auth, how we get the token from third-party serve.
|
||||
* When authSchema is BEARER you must define this field.
|
||||
*/
|
||||
private ForBearerTokenEnum forBearerTokenEnum;
|
||||
|
||||
/**
|
||||
* When do pre-auth for bearer auth, we get the response from third-party server which contains the token.
|
||||
* Use this strategy to extract the token from response body.
|
||||
* By default, search for field like "token":"xxxxxxxx" in response.
|
||||
*/
|
||||
private GetTokenFromResponseStrategy getTokenFromResponseStrategy = body -> {
|
||||
try {
|
||||
int i1 = body.indexOf("\"token\"") + 7;
|
||||
int i2 = body.indexOf(':', i1);
|
||||
int i3 = body.indexOf("\"", i2) + 1;
|
||||
int i4 = body.indexOf("\"", i3 + 1);
|
||||
return body.substring(i3, i4);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
public HttpApiConfig() {
|
||||
}
|
||||
|
||||
public HttpApiConfig(HttpApiConfig httpApiConfig, String loginUrl) {
|
||||
this.authSchema = httpApiConfig.authSchema;
|
||||
this.httpMethod = httpApiConfig.httpMethod;
|
||||
this.loginUrl = loginUrl;
|
||||
this.authInfoField = httpApiConfig.authInfoField;
|
||||
this.customHeaders = httpApiConfig.customHeaders;
|
||||
this.customParams = httpApiConfig.customParams;
|
||||
this.customBody = httpApiConfig.customBody;
|
||||
this.bearerTokenIssueUrl = httpApiConfig.bearerTokenIssueUrl;
|
||||
this.requestBodyToJapUserStrategy = httpApiConfig.requestBodyToJapUserStrategy;
|
||||
this.forBearerTokenEnum = httpApiConfig.forBearerTokenEnum;
|
||||
this.getTokenFromResponseStrategy = httpApiConfig.getTokenFromResponseStrategy;
|
||||
}
|
||||
|
||||
public AuthSchemaEnum getAuthSchema() {
|
||||
return authSchema;
|
||||
}
|
||||
|
||||
public HttpApiConfig setAuthSchema(AuthSchemaEnum authSchema) {
|
||||
this.authSchema = authSchema;
|
||||
return this;
|
||||
}
|
||||
|
||||
public HttpMethodEnum getHttpMethod() {
|
||||
return httpMethod;
|
||||
}
|
||||
|
||||
public HttpApiConfig setHttpMethod(HttpMethodEnum httpMethod) {
|
||||
this.httpMethod = httpMethod;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getLoginUrl() {
|
||||
return loginUrl;
|
||||
}
|
||||
|
||||
public HttpApiConfig setLoginUrl(String loginUrl) {
|
||||
this.loginUrl = loginUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AuthInfoFieldEnum getAuthInfoField() {
|
||||
return authInfoField;
|
||||
}
|
||||
|
||||
public HttpApiConfig setAuthInfoField(AuthInfoFieldEnum authInfoField) {
|
||||
this.authInfoField = authInfoField;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Map<String, String> getCustomHeaders() {
|
||||
return customHeaders;
|
||||
}
|
||||
|
||||
public HttpApiConfig setCustomHeaders(Map<String, String> customHeaders) {
|
||||
this.customHeaders = customHeaders;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RequestBodyToJapUserStrategy getRequestBodyToJapUserStrategy() {
|
||||
return requestBodyToJapUserStrategy;
|
||||
}
|
||||
|
||||
public HttpApiConfig setRequestBodyToJapUserStrategy(RequestBodyToJapUserStrategy requestBodyToJapUserStrategy) {
|
||||
this.requestBodyToJapUserStrategy = requestBodyToJapUserStrategy;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Map<String, String> getCustomParams() {
|
||||
return customParams;
|
||||
}
|
||||
|
||||
public HttpApiConfig setCustomParams(Map<String, String> customParams) {
|
||||
this.customParams = customParams;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Map<String, Object> getCustomParamsObjects() {
|
||||
return new HashMap<>(customParams);
|
||||
}
|
||||
|
||||
public Map<String, String> getCustomBody() {
|
||||
return customBody;
|
||||
}
|
||||
|
||||
public HttpApiConfig setCustomBody(Map<String, String> customBody) {
|
||||
this.customBody = customBody;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ForBearerTokenEnum getForBearerTokenEnum() {
|
||||
return forBearerTokenEnum;
|
||||
}
|
||||
|
||||
public HttpApiConfig setForBearerTokenEnum(ForBearerTokenEnum forBearerTokenEnum) {
|
||||
this.forBearerTokenEnum = forBearerTokenEnum;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GetTokenFromResponseStrategy getGetTokenFromResponseStrategy() {
|
||||
return getTokenFromResponseStrategy;
|
||||
}
|
||||
|
||||
public HttpApiConfig setGetTokenFromResponseStrategy(GetTokenFromResponseStrategy getTokenFromResponseStrategy) {
|
||||
this.getTokenFromResponseStrategy = getTokenFromResponseStrategy;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getBearerTokenIssueUrl() {
|
||||
return bearerTokenIssueUrl;
|
||||
}
|
||||
|
||||
public HttpApiConfig setBearerTokenIssueUrl(String bearerTokenIssueUrl) {
|
||||
this.bearerTokenIssueUrl = bearerTokenIssueUrl;
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,335 @@
|
||||
package com.fujieid.jap.httpapi;
|
||||
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import com.fujieid.jap.core.JapUser;
|
||||
import com.fujieid.jap.core.JapUserService;
|
||||
import com.fujieid.jap.core.cache.JapCache;
|
||||
import com.fujieid.jap.core.config.AuthenticateConfig;
|
||||
import com.fujieid.jap.core.config.JapConfig;
|
||||
import com.fujieid.jap.core.exception.JapException;
|
||||
import com.fujieid.jap.core.result.JapErrorCode;
|
||||
import com.fujieid.jap.core.result.JapResponse;
|
||||
import com.fujieid.jap.core.strategy.AbstractJapStrategy;
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.http.JapHttpResponse;
|
||||
import com.fujieid.jap.httpapi.enums.AuthSchemaEnum;
|
||||
import com.fujieid.jap.httpapi.enums.HttpMethodEnum;
|
||||
import com.fujieid.jap.httpapi.subject.DigestAuthorizationSubject;
|
||||
import com.fujieid.jap.httpapi.subject.DigestWwwAuthenticateSubject;
|
||||
import com.fujieid.jap.httpapi.subject.HttpAuthResponse;
|
||||
import com.fujieid.jap.httpapi.util.*;
|
||||
|
||||
/**
|
||||
* The strategy for jap-http-api module to request third party system.
|
||||
*
|
||||
* @author zhihai.yu (mvbbb(a)foxmail.com)
|
||||
* @version 1.0.0
|
||||
* @since 1.0.5
|
||||
*/
|
||||
public class HttpApiStrategy extends AbstractJapStrategy {
|
||||
|
||||
|
||||
public HttpApiStrategy(JapUserService japUserService, JapConfig japConfig, JapCache japCache) {
|
||||
super(japUserService, japConfig, japCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JapResponse authenticate(AuthenticateConfig config, JapHttpRequest request, JapHttpResponse response) {
|
||||
try {
|
||||
checkAuthenticateConfig(config, HttpApiConfig.class);
|
||||
} catch (JapException e) {
|
||||
e.printStackTrace();
|
||||
return JapResponse.error(e.getErrorCode(), e.getErrorMessage());
|
||||
}
|
||||
HttpApiConfig httpApiConfig = (HttpApiConfig) config;
|
||||
|
||||
return this.doAuthenticate(httpApiConfig, request, response);
|
||||
}
|
||||
|
||||
private JapResponse doAuthenticate(HttpApiConfig config, JapHttpRequest request, JapHttpResponse response) {
|
||||
|
||||
HttpAuthResponse authResponse = null;
|
||||
JapUser japUser = null;
|
||||
|
||||
try {
|
||||
japUser = getJapUser(request, config);
|
||||
|
||||
if (japUser == null) {
|
||||
return JapResponse.error(JapErrorCode.MISS_CREDENTIALS);
|
||||
}
|
||||
|
||||
switch (config.getAuthSchema()) {
|
||||
case BASIC:
|
||||
authResponse = doBasicAuth(japUser, config, response);
|
||||
break;
|
||||
case DIGEST:
|
||||
authResponse = doDigestAuth(japUser, config, response);
|
||||
break;
|
||||
case BEARER:
|
||||
authResponse = doBearerAuth(japUser, config, response);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} catch (JapException e) {
|
||||
return JapResponse.error(e.getErrorCode(), e.getErrorMessage());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (authResponse != null && authResponse.isSuccess()) {
|
||||
if (config.getAuthSchema() == AuthSchemaEnum.BASIC || config.getAuthSchema() == AuthSchemaEnum.DIGEST) {
|
||||
japUserService.createAndGetHttpApiUser(japUser);
|
||||
}
|
||||
return JapResponse.success(authResponse.getBody());
|
||||
} else {
|
||||
return JapResponse.error(JapErrorCode.INVALID_PASSWORD);
|
||||
}
|
||||
}
|
||||
|
||||
private HttpAuthResponse doDigestAuth(JapUser japUser, HttpApiConfig config, JapHttpResponse response) {
|
||||
|
||||
/*
|
||||
* send a request to third-party server to get a random number and encryption algorithm
|
||||
* see: https://datatracker.ietf.org/doc/html/rfc2069#section-2.1.1
|
||||
*/
|
||||
HttpAuthResponse responseForWWWAuth = HttpAuthUtil.sendRequest(config.getLoginUrl(),
|
||||
HttpMethodEnum.GET,
|
||||
config.getCustomHeaders(),
|
||||
config.getCustomParams(),
|
||||
SimpleAuthJsonUtil.getJsonStrByParams(config.getCustomBody()));
|
||||
|
||||
if (responseForWWWAuth == null || responseForWWWAuth.getHeaders() == null) {
|
||||
return null;
|
||||
}
|
||||
HttpAuthResponse result = null;
|
||||
String wwwAuthenticate = null;
|
||||
|
||||
try {
|
||||
wwwAuthenticate = responseForWWWAuth.getHeaders().get("WWW-Authenticate").get(0).replaceFirst("Digest ", "");
|
||||
DigestWwwAuthenticateSubject wwwAuthenticateSubject = SubjectSerializeUtil.deserialize(wwwAuthenticate, DigestWwwAuthenticateSubject.class);
|
||||
|
||||
String username = japUser.getUsername();
|
||||
String realm = wwwAuthenticateSubject.getRealm();
|
||||
String password = japUser.getPassword();
|
||||
String method = config.getHttpMethod().toString().toUpperCase();
|
||||
String digestUri = URLUtil.getRelativeUri(config.getLoginUrl());
|
||||
String nonce = wwwAuthenticateSubject.getNonce();
|
||||
String qop = wwwAuthenticateSubject.getQop();
|
||||
String nc = DigestUtil.getNc();
|
||||
String cnonce = DigestUtil.getCnonce();
|
||||
String opaque = wwwAuthenticateSubject.getOpaque();
|
||||
|
||||
String ha1 = DigestMD5Util.encode(username, realm, password);
|
||||
String ha2 = DigestUtil.getHa2ByQop(qop, method, digestUri);
|
||||
String qopResponse = DigestUtil.getResponseByQop(ha1, nonce, nc, cnonce, qop, ha2);
|
||||
|
||||
DigestAuthorizationSubject authorizationSubject = new DigestAuthorizationSubject()
|
||||
.setCnonce(cnonce)
|
||||
.setQop(qop)
|
||||
.setNc(nc)
|
||||
.setNonce(nonce)
|
||||
.setRealm(realm)
|
||||
.setUsername(username)
|
||||
.setUri(digestUri)
|
||||
.setResponse(qopResponse)
|
||||
.setAlgorithm(wwwAuthenticateSubject.getAlgorithm())
|
||||
.setOpaque(opaque);
|
||||
|
||||
String authStr = SubjectSerializeUtil.serialize(authorizationSubject);
|
||||
|
||||
// send authorization request
|
||||
config.getCustomHeaders().put("Authorization", "Digest " + authStr);
|
||||
result = HttpAuthUtil.sendRequest(config.getLoginUrl(),
|
||||
config.getHttpMethod(),
|
||||
config.getCustomHeaders(),
|
||||
config.getCustomParams(),
|
||||
SimpleAuthJsonUtil.getJsonStrByParams(config.getCustomBody()));
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private HttpAuthResponse doBasicAuth(JapUser japUser, HttpApiConfig config, JapHttpResponse response) {
|
||||
|
||||
/*
|
||||
* see: The 'Basic' HTTP Authentication Scheme:https://datatracker.ietf.org/doc/html/rfc7617
|
||||
*/
|
||||
String basicAuth = "Basic " + Base64.encode(japUser.getUsername() + ":" + japUser.getPassword());
|
||||
config.getCustomHeaders().put("authorization", basicAuth);
|
||||
|
||||
return HttpAuthUtil.sendRequest(config.getLoginUrl(),
|
||||
config.getHttpMethod(),
|
||||
config.getCustomHeaders(),
|
||||
config.getCustomParams(),
|
||||
SimpleAuthJsonUtil.getJsonStrByParams(config.getCustomBody()));
|
||||
}
|
||||
|
||||
private HttpAuthResponse sendBearerTokenAuthRequest(String token, HttpApiConfig config) {
|
||||
String bearerToken = "Bearer " + token;
|
||||
config.getCustomHeaders().put("Authorization", bearerToken);
|
||||
return HttpAuthUtil.sendRequest(config.getLoginUrl(),
|
||||
config.getHttpMethod(),
|
||||
config.getCustomHeaders(),
|
||||
config.getCustomParams(),
|
||||
SimpleAuthJsonUtil.getJsonStrByParams(config.getCustomBody()));
|
||||
}
|
||||
|
||||
private HttpAuthResponse doBearerAuth(JapUser japUser, HttpApiConfig config, JapHttpResponse response) {
|
||||
|
||||
JapUser japUserInDb = japUserService.getByName(japUser.getUsername());
|
||||
String token = null;
|
||||
if (japUserInDb == null || japUserInDb.getToken() == null) {
|
||||
token = doPreAuthForBearerToken(japUser, config, response);
|
||||
} else {
|
||||
token = japUserInDb.getToken();
|
||||
}
|
||||
|
||||
HttpAuthResponse result = sendBearerTokenAuthRequest(token, config);
|
||||
|
||||
// old token expired, request for new token
|
||||
if (result == null || !result.isSuccess()) {
|
||||
String newToken = doPreAuthForBearerToken(japUser, config, response);
|
||||
result = sendBearerTokenAuthRequest(newToken, config);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* do a pre-auth in Bearer auth to get token for this user
|
||||
*
|
||||
* @param japUser jap user
|
||||
* @param config Http api config
|
||||
* @param response current http response
|
||||
*/
|
||||
private String doPreAuthForBearerToken(JapUser japUser, HttpApiConfig config, JapHttpResponse response) {
|
||||
HttpAuthResponse httpAuthResponse = null;
|
||||
// clean old auth token
|
||||
config.getCustomHeaders().remove("Authorization");
|
||||
config.getCustomHeaders().remove("authorization");
|
||||
switch (config.getForBearerTokenEnum()) {
|
||||
case BY_BASIC:
|
||||
httpAuthResponse = this.doBasicAuth(japUser, new HttpApiConfig(config, config.getBearerTokenIssueUrl()), response);
|
||||
break;
|
||||
case BY_DIGEST:
|
||||
httpAuthResponse = this.doDigestAuth(japUser, new HttpApiConfig(config, config.getBearerTokenIssueUrl()), response);
|
||||
break;
|
||||
case BY_HEADER:
|
||||
config.getCustomHeaders().put("username", japUser.getUsername());
|
||||
config.getCustomHeaders().put("password", japUser.getPassword());
|
||||
httpAuthResponse = HttpAuthUtil.sendRequest(config.getLoginUrl(),
|
||||
config.getHttpMethod(),
|
||||
config.getCustomHeaders(),
|
||||
config.getCustomParams(),
|
||||
SimpleAuthJsonUtil.getJsonStrByParams(config.getCustomBody()));
|
||||
break;
|
||||
case BY_PARAMS:
|
||||
config.getCustomParams().put("username", japUser.getUsername());
|
||||
config.getCustomParams().put("password", japUser.getPassword());
|
||||
httpAuthResponse = HttpAuthUtil.sendRequest(config.getLoginUrl(),
|
||||
config.getHttpMethod(),
|
||||
config.getCustomHeaders(),
|
||||
config.getCustomParams(),
|
||||
SimpleAuthJsonUtil.getJsonStrByParams(config.getCustomBody()));
|
||||
break;
|
||||
case BY_BODY:
|
||||
String body = SimpleAuthJsonUtil.getJsonStrByJapUserAndParams(japUser, config.getCustomBody());
|
||||
httpAuthResponse = HttpAuthUtil.sendRequest(config.getLoginUrl(),
|
||||
config.getHttpMethod(),
|
||||
config.getCustomHeaders(),
|
||||
config.getCustomParams(),
|
||||
body);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// pre-auth field
|
||||
if (httpAuthResponse == null || !httpAuthResponse.isSuccess()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// get token from httpAuthResponse body
|
||||
String token = config.getGetTokenFromResponseStrategy().getToken(httpAuthResponse.getBody());
|
||||
if (token == null || token.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// save jap user to db
|
||||
japUser.setToken(token);
|
||||
japUserService.createAndGetHttpApiUser(japUser);
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* get user information from request according to http api config.
|
||||
*
|
||||
* @param request current http request
|
||||
* @param config http api config
|
||||
* @return jap user contains username and password
|
||||
*/
|
||||
public JapUser getJapUser(JapHttpRequest request, HttpApiConfig config) {
|
||||
JapUser japUser = null;
|
||||
String username = null;
|
||||
String password = null;
|
||||
|
||||
switch (config.getAuthInfoField()) {
|
||||
case PARAMS:
|
||||
username = request.getParameter("username");
|
||||
password = request.getParameter("password");
|
||||
japUser = new JapUser().setUsername(username).setPassword(password);
|
||||
break;
|
||||
|
||||
case HEADER:
|
||||
username = request.getHeader("username");
|
||||
password = request.getHeader("password");
|
||||
japUser = new JapUser().setUsername(username).setPassword(password);
|
||||
break;
|
||||
|
||||
case BODY:
|
||||
try {
|
||||
// get auth info body from request body.
|
||||
japUser = config.getRequestBodyToJapUserStrategy().decode(request);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (null == japUser || null == japUser.getUsername()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return japUser;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* check http api config.
|
||||
* NOTICE:
|
||||
* 1. When use "GET" as request method, custom body is not supported.
|
||||
* 2. Can not custom body and params at the same time.
|
||||
*
|
||||
* @param sourceConfig The parameters passed in by the caller
|
||||
* @param targetConfigClazz The actual parameter class type
|
||||
* @throws JapException Jap exception will be thrown when http api config configuration error
|
||||
*/
|
||||
@Override
|
||||
protected void checkAuthenticateConfig(AuthenticateConfig sourceConfig, Class<?> targetConfigClazz) throws JapException {
|
||||
super.checkAuthenticateConfig(sourceConfig, targetConfigClazz);
|
||||
HttpApiConfig config = (HttpApiConfig) sourceConfig;
|
||||
if (config == null ||
|
||||
config.getAuthSchema() == null ||
|
||||
config.getHttpMethod() == null ||
|
||||
config.getLoginUrl() == null ||
|
||||
config.getAuthInfoField() == null ||
|
||||
(config.getHttpMethod() == HttpMethodEnum.GET && (config.getCustomBody() != null && config.getCustomBody().size() != 0)) ||
|
||||
((config.getCustomBody() != null && config.getCustomBody().size() != 0) && (config.getCustomParams() != null && config.getCustomParams().size() != 0))
|
||||
) {
|
||||
throw new JapException(JapErrorCode.ERROR_HTTP_API_CONFIG);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package com.fujieid.jap.httpapi.enums;
|
||||
|
||||
/**
|
||||
* @author zhihai.yu (mvbbb(a)foxmail.com)
|
||||
* @version 1.0.0
|
||||
* @since 1.0.5
|
||||
*/
|
||||
public enum AuthInfoFieldEnum {
|
||||
HEADER,
|
||||
PARAMS,
|
||||
BODY
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package com.fujieid.jap.httpapi.enums;
|
||||
|
||||
/**
|
||||
* @author zhihai.yu (mvbbb(a)foxmail.com)
|
||||
* @version 1.0.0
|
||||
* @since 1.0.5
|
||||
*/
|
||||
public enum AuthSchemaEnum {
|
||||
BASIC,
|
||||
DIGEST,
|
||||
BEARER
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package com.fujieid.jap.httpapi.enums;
|
||||
|
||||
/**
|
||||
* @author zhihai.yu (mvbbb(a)foxmail.com)
|
||||
* @version 1.0.0
|
||||
* @since 1.0.5
|
||||
*/
|
||||
public enum ForBearerTokenEnum {
|
||||
BY_HEADER,
|
||||
BY_PARAMS,
|
||||
BY_BODY,
|
||||
BY_BASIC,
|
||||
BY_DIGEST
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package com.fujieid.jap.httpapi.enums;
|
||||
|
||||
/**
|
||||
* @author zhihai.yu (mvbbb(a)foxmail.com)
|
||||
* @version 1.0.0
|
||||
* @since 1.0.5
|
||||
*/
|
||||
public enum HttpMethodEnum {
|
||||
POST,
|
||||
GET
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.fujieid.jap.httpapi.strategy;
|
||||
|
||||
/**
|
||||
* Define how to get token from the third-party server's response when request to issue a bearer token
|
||||
*
|
||||
* @author zhihai.yu (mvbbb(a)foxmail.com)
|
||||
* @version 1.0.0
|
||||
* @since 1.0.5
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface GetTokenFromResponseStrategy {
|
||||
|
||||
/**
|
||||
* get token from body
|
||||
*
|
||||
* @param body response body
|
||||
* @return token
|
||||
*/
|
||||
String getToken(String body);
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package com.fujieid.jap.httpapi.strategy;
|
||||
|
||||
import com.fujieid.jap.core.JapUser;
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
|
||||
/**
|
||||
* Implement this functional interface if your auth info in the request body is not standard json format.
|
||||
*
|
||||
* @author zhihai.yu (mvbbb(a)foxmail.com)
|
||||
* @version 1.0.0
|
||||
* @since 1.0.5
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface RequestBodyToJapUserStrategy {
|
||||
/**
|
||||
* get a JapUser from request
|
||||
*
|
||||
* @param request request
|
||||
* @return JapUser
|
||||
* @throws Exception When the data in the request cannot be decoded, an exception will be thrown
|
||||
*/
|
||||
JapUser decode(JapHttpRequest request) throws Exception;
|
||||
}
|
@ -0,0 +1,133 @@
|
||||
package com.fujieid.jap.httpapi.subject;
|
||||
|
||||
/**
|
||||
* The Authorization Request Header
|
||||
*
|
||||
* @author zhihai.yu (mvbbb(a)foxmail.com)
|
||||
* @version 1.0.0
|
||||
* @see <a href="https://en.wikipedia.org/wiki/Digest_access_authentication" target="_blank">https://en.wikipedia.org/wiki/Digest_access_authentication</a>
|
||||
* @see <a href="https://datatracker.ietf.org/doc/html/rfc2069#section-2.1.2" target="_blank">https://datatracker.ietf.org/doc/html/rfc2069#section-2.1.2</a>
|
||||
* @since 1.0.5
|
||||
*/
|
||||
public class DigestAuthorizationSubject {
|
||||
private String username;
|
||||
private String realm;
|
||||
private String nonce;
|
||||
private String uri;
|
||||
private String response;
|
||||
private String qop;
|
||||
private String nc;
|
||||
private String cnonce;
|
||||
private String pop;
|
||||
private String opaque;
|
||||
private String digest;
|
||||
private String algorithm;
|
||||
|
||||
public String getQop() {
|
||||
return qop;
|
||||
}
|
||||
|
||||
public DigestAuthorizationSubject setQop(String qop) {
|
||||
this.qop = qop;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public DigestAuthorizationSubject setUsername(String username) {
|
||||
this.username = username;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getRealm() {
|
||||
return realm;
|
||||
}
|
||||
|
||||
public DigestAuthorizationSubject setRealm(String realm) {
|
||||
this.realm = realm;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getNonce() {
|
||||
return nonce;
|
||||
}
|
||||
|
||||
public DigestAuthorizationSubject setNonce(String nonce) {
|
||||
this.nonce = nonce;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getUri() {
|
||||
return uri;
|
||||
}
|
||||
|
||||
public DigestAuthorizationSubject setUri(String uri) {
|
||||
this.uri = uri;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getPop() {
|
||||
return pop;
|
||||
}
|
||||
|
||||
public DigestAuthorizationSubject setPop(String pop) {
|
||||
this.pop = pop;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getNc() {
|
||||
return nc;
|
||||
}
|
||||
|
||||
public DigestAuthorizationSubject setNc(String nc) {
|
||||
this.nc = nc;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getCnonce() {
|
||||
return cnonce;
|
||||
}
|
||||
|
||||
public DigestAuthorizationSubject setCnonce(String cnonce) {
|
||||
this.cnonce = cnonce;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getResponse() {
|
||||
return response;
|
||||
}
|
||||
|
||||
public DigestAuthorizationSubject setResponse(String response) {
|
||||
this.response = response;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getOpaque() {
|
||||
return opaque;
|
||||
}
|
||||
|
||||
public DigestAuthorizationSubject setOpaque(String opaque) {
|
||||
this.opaque = opaque;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getDigest() {
|
||||
return digest;
|
||||
}
|
||||
|
||||
public DigestAuthorizationSubject setDigest(String digest) {
|
||||
this.digest = digest;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getAlgorithm() {
|
||||
return algorithm;
|
||||
}
|
||||
|
||||
public DigestAuthorizationSubject setAlgorithm(String algorithm) {
|
||||
this.algorithm = algorithm;
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
package com.fujieid.jap.httpapi.subject;
|
||||
|
||||
/**
|
||||
* The WWW-Authenticate Response Header
|
||||
*
|
||||
* @author zhihai.yu (mvbbb(a)foxmail.com)
|
||||
* @version 1.0.0
|
||||
* @see <a href="https://datatracker.ietf.org/doc/html/rfc2069#section-2.1.1" target="_blank">https://datatracker.ietf.org/doc/html/rfc2069#section-2.1.1</a>
|
||||
* @since 1.0.5
|
||||
*/
|
||||
public class DigestWwwAuthenticateSubject {
|
||||
private String realm;
|
||||
private String domain;
|
||||
private String nonce;
|
||||
private String opaque;
|
||||
private String algorithm;
|
||||
private String stale;
|
||||
private String qop;
|
||||
|
||||
public DigestWwwAuthenticateSubject() {
|
||||
}
|
||||
|
||||
public String getQop() {
|
||||
return qop;
|
||||
}
|
||||
|
||||
public DigestWwwAuthenticateSubject setQop(String qop) {
|
||||
this.qop = qop;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getRealm() {
|
||||
return realm;
|
||||
}
|
||||
|
||||
public DigestWwwAuthenticateSubject setRealm(String realm) {
|
||||
this.realm = realm;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getDomain() {
|
||||
return domain;
|
||||
}
|
||||
|
||||
public DigestWwwAuthenticateSubject setDomain(String domain) {
|
||||
this.domain = domain;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getNonce() {
|
||||
return nonce;
|
||||
}
|
||||
|
||||
public DigestWwwAuthenticateSubject setNonce(String nonce) {
|
||||
this.nonce = nonce;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getOpaque() {
|
||||
return opaque;
|
||||
}
|
||||
|
||||
public DigestWwwAuthenticateSubject setOpaque(String opaque) {
|
||||
this.opaque = opaque;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getAlgorithm() {
|
||||
return algorithm;
|
||||
}
|
||||
|
||||
public DigestWwwAuthenticateSubject setAlgorithm(String algorithm) {
|
||||
this.algorithm = algorithm;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getStale() {
|
||||
return stale;
|
||||
}
|
||||
|
||||
public DigestWwwAuthenticateSubject setStale(String stale) {
|
||||
this.stale = stale;
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package com.fujieid.jap.httpapi.subject;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* packaging auth result
|
||||
*
|
||||
* @author zhihai.yu (mvbbb(a)foxmail.com)
|
||||
* @version 1.0.0
|
||||
* @since 1.0.5
|
||||
*/
|
||||
public class HttpAuthResponse {
|
||||
private boolean success;
|
||||
private String body;
|
||||
private Map<String, List<String>> headers;
|
||||
|
||||
public HttpAuthResponse(boolean success, String body, Map<String, List<String>> headers) {
|
||||
this.success = success;
|
||||
this.body = body;
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
public boolean isSuccess() {
|
||||
return success;
|
||||
}
|
||||
|
||||
public HttpAuthResponse setSuccess(boolean success) {
|
||||
this.success = success;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public HttpAuthResponse setBody(String body) {
|
||||
this.body = body;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Map<String, List<String>> getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
public HttpAuthResponse setHeaders(Map<String, List<String>> headers) {
|
||||
this.headers = headers;
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package com.fujieid.jap.httpapi.util;
|
||||
|
||||
import com.fujieid.jap.core.exception.JapException;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* Splice strings by ":", and encode using md5. eg:"MD5(MD5(username:realm:password):nonce:cnonce)"
|
||||
*
|
||||
* @author zhihai.yu (mvbbb(a)foxmail.com)
|
||||
* @version 1.0.0
|
||||
* @since 1.0.5
|
||||
*/
|
||||
public final class DigestMD5Util {
|
||||
|
||||
private final static String[] HEX_ARRAY = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};
|
||||
|
||||
public static String encode(String... strs) {
|
||||
StringBuilder stringBuffer = new StringBuilder();
|
||||
boolean isFirst = true;
|
||||
for (String str : strs) {
|
||||
if (isFirst) {
|
||||
stringBuffer.append(str);
|
||||
isFirst = false;
|
||||
} else {
|
||||
stringBuffer.append(":").append(str);
|
||||
}
|
||||
}
|
||||
|
||||
// Create an information summary with MD5 algorithm
|
||||
MessageDigest md = null;
|
||||
String algorithm = "MD5";
|
||||
try {
|
||||
md = MessageDigest.getInstance(algorithm);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
throw new JapException(algorithm + " not found");
|
||||
}
|
||||
byte[] bytes = md.digest(stringBuffer.toString().getBytes());
|
||||
return byteArrayToHex(bytes);
|
||||
|
||||
}
|
||||
|
||||
private static String byteArrayToHex(byte[] b) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (byte value : b) {
|
||||
sb.append(byteToHex(value));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String byteToHex(byte b) {
|
||||
int n = b;
|
||||
if (n < 0) {
|
||||
n = n + 256;
|
||||
}
|
||||
int d1 = n / 16;
|
||||
int d2 = n % 16;
|
||||
return HEX_ARRAY[d1] + HEX_ARRAY[d2];
|
||||
}
|
||||
}
|
@ -0,0 +1,164 @@
|
||||
package com.fujieid.jap.httpapi.util;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
/**
|
||||
* refer: https://github.com/meyfa/java-sha256/blob/master/src/main/java/net/meyfa/sha256/Sha256.java
|
||||
*
|
||||
* @author zhihai.yu (mvbbb(a)foxmail.com)
|
||||
* @version 1.0.0
|
||||
* @since 1.0.5
|
||||
*/
|
||||
public class DigestSha256Util {
|
||||
private static final int[] K = {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
};
|
||||
|
||||
private static final int[] H0 = {
|
||||
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
|
||||
};
|
||||
|
||||
private static final int BLOCK_BITS = 512;
|
||||
private static final int BLOCK_BYTES = BLOCK_BITS / 8;
|
||||
|
||||
// working arrays
|
||||
private static final int[] W = new int[64];
|
||||
private static final int[] H = new int[8];
|
||||
private static final int[] TEMP = new int[8];
|
||||
|
||||
/**
|
||||
* Hashes the given message with SHA-256 and returns the hash.
|
||||
*
|
||||
* @param message The bytes to hash.
|
||||
* @return The hash's bytes.
|
||||
*/
|
||||
public static byte[] hash(byte[] message) {
|
||||
// let H = H0
|
||||
System.arraycopy(H0, 0, H, 0, H0.length);
|
||||
|
||||
// initialize all words
|
||||
int[] words = pad(message);
|
||||
|
||||
// enumerate all blocks (each containing 16 words)
|
||||
for (int i = 0, n = words.length / 16; i < n; ++i) {
|
||||
|
||||
// initialize W from the block's words
|
||||
System.arraycopy(words, i * 16, W, 0, 16);
|
||||
for (int t = 16; t < W.length; ++t) {
|
||||
W[t] = smallSig1(W[t - 2]) + W[t - 7] + smallSig0(W[t - 15]) + W[t - 16];
|
||||
}
|
||||
|
||||
// let TEMP = H
|
||||
System.arraycopy(H, 0, TEMP, 0, H.length);
|
||||
|
||||
// operate on TEMP
|
||||
for (int t = 0; t < W.length; ++t) {
|
||||
int t1 = TEMP[7] + bigSig1(TEMP[4]) + ch(TEMP[4], TEMP[5], TEMP[6]) + K[t] + W[t];
|
||||
int t2 = bigSig0(TEMP[0]) + maj(TEMP[0], TEMP[1], TEMP[2]);
|
||||
System.arraycopy(TEMP, 0, TEMP, 1, TEMP.length - 1);
|
||||
TEMP[4] += t1;
|
||||
TEMP[0] = t1 + t2;
|
||||
}
|
||||
|
||||
// add values in TEMP to values in H
|
||||
for (int t = 0; t < H.length; ++t) {
|
||||
H[t] += TEMP[t];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return toByteArray(H);
|
||||
}
|
||||
|
||||
/**
|
||||
* <b>Internal method, no need to call.</b> Pads the given message to have a length
|
||||
* that is a multiple of 512 bits (64 bytes), including the addition of a
|
||||
* 1-bit, k 0-bits, and the message length as a 64-bit integer.
|
||||
* The result is a 32-bit integer array with big-endian byte representation.
|
||||
*
|
||||
* @param message The message to pad.
|
||||
* @return A new array with the padded message bytes.
|
||||
*/
|
||||
public static int[] pad(byte[] message) {
|
||||
// new message length: original + 1-bit and padding + 8-byte length
|
||||
// --> block count: whole blocks + (padding + length rounded up)
|
||||
int finalBlockLength = message.length % BLOCK_BYTES;
|
||||
int blockCount = message.length / BLOCK_BYTES + (finalBlockLength + 1 + 8 > BLOCK_BYTES ? 2 : 1);
|
||||
|
||||
final IntBuffer result = IntBuffer.allocate(blockCount * (BLOCK_BYTES / Integer.BYTES));
|
||||
|
||||
// copy as much of the message as possible
|
||||
ByteBuffer buf = ByteBuffer.wrap(message);
|
||||
for (int i = 0, n = message.length / Integer.BYTES; i < n; ++i) {
|
||||
result.put(buf.getInt());
|
||||
}
|
||||
// copy the remaining bytes (less than 4) and append 1 bit (rest is zero)
|
||||
ByteBuffer remainder = ByteBuffer.allocate(4);
|
||||
remainder.put(buf).put((byte) 0b10000000).rewind();
|
||||
result.put(remainder.getInt());
|
||||
|
||||
// ignore however many pad bytes (implicitly calculated in the beginning)
|
||||
result.position(result.capacity() - 2);
|
||||
// place original message length as 64-bit integer at the end
|
||||
long msgLength = message.length * 8L;
|
||||
result.put((int) (msgLength >>> 32));
|
||||
result.put((int) msgLength);
|
||||
|
||||
return result.array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given int array into a byte array via big-endian conversion
|
||||
* (1 int becomes 4 bytes).
|
||||
*
|
||||
* @param ints The source array.
|
||||
* @return The converted array.
|
||||
*/
|
||||
private static byte[] toByteArray(int[] ints) {
|
||||
ByteBuffer buf = ByteBuffer.allocate(ints.length * Integer.BYTES);
|
||||
for (int i : ints) {
|
||||
buf.putInt(i);
|
||||
}
|
||||
return buf.array();
|
||||
}
|
||||
|
||||
private static int ch(int x, int y, int z) {
|
||||
return (x & y) | ((~x) & z);
|
||||
}
|
||||
|
||||
private static int maj(int x, int y, int z) {
|
||||
return (x & y) | (x & z) | (y & z);
|
||||
}
|
||||
|
||||
private static int bigSig0(int x) {
|
||||
return Integer.rotateRight(x, 2)
|
||||
^ Integer.rotateRight(x, 13)
|
||||
^ Integer.rotateRight(x, 22);
|
||||
}
|
||||
|
||||
private static int bigSig1(int x) {
|
||||
return Integer.rotateRight(x, 6)
|
||||
^ Integer.rotateRight(x, 11)
|
||||
^ Integer.rotateRight(x, 25);
|
||||
}
|
||||
|
||||
private static int smallSig0(int x) {
|
||||
return Integer.rotateRight(x, 7)
|
||||
^ Integer.rotateRight(x, 18)
|
||||
^ (x >>> 3);
|
||||
}
|
||||
|
||||
private static int smallSig1(int x) {
|
||||
return Integer.rotateRight(x, 17)
|
||||
^ Integer.rotateRight(x, 19)
|
||||
^ (x >>> 10);
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package com.fujieid.jap.httpapi.util;
|
||||
|
||||
|
||||
import cn.hutool.core.lang.UUID;
|
||||
|
||||
import java.util.concurrent.atomic.LongAdder;
|
||||
|
||||
/**
|
||||
* @author zhihai.yu (mvbbb(a)foxmail.com)
|
||||
* @version 1.0.0
|
||||
* @since 1.0.5
|
||||
*/
|
||||
public final class DigestUtil {
|
||||
|
||||
private static final LongAdder LONG_ADDER = new LongAdder();
|
||||
|
||||
public static String getCnonce() {
|
||||
return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 16);
|
||||
}
|
||||
|
||||
public static String getNc() {
|
||||
LONG_ADDER.increment();
|
||||
return LONG_ADDER.toString();
|
||||
}
|
||||
|
||||
public static String getResponseByQop(String ha1, String nonce, String nc, String cnonce, String qop, String ha2) {
|
||||
if (qop != null && (qop.contains("auth") || qop.contains("auth-init"))) {
|
||||
return DigestMD5Util.encode(ha1, nonce, nc, cnonce, qop, ha2);
|
||||
} else {
|
||||
return DigestMD5Util.encode(ha1, nonce, ha2);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getHa2ByQop(String qop, String method, String digestUri) {
|
||||
if (qop == null || !qop.contains("auth-init")) {
|
||||
return DigestMD5Util.encode(method, digestUri);
|
||||
} else {
|
||||
// TODO Support "auth-init" ha2 compute method
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package com.fujieid.jap.httpapi.util;
|
||||
|
||||
import com.fujieid.jap.httpapi.enums.HttpMethodEnum;
|
||||
import com.fujieid.jap.httpapi.subject.HttpAuthResponse;
|
||||
import com.xkcoding.http.HttpUtil;
|
||||
import com.xkcoding.http.support.HttpHeader;
|
||||
import com.xkcoding.http.support.SimpleHttpResponse;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author zhihai.yu (mvbbb(a)foxmail.com)
|
||||
* @version 1.0.0
|
||||
* @since 1.0.5
|
||||
*/
|
||||
public final class HttpAuthUtil {
|
||||
|
||||
public static HttpAuthResponse sendRequest(String url,
|
||||
HttpMethodEnum method,
|
||||
Map<String, String> header,
|
||||
Map<String, String> params,
|
||||
String body) {
|
||||
SimpleHttpResponse response = null;
|
||||
switch (method) {
|
||||
case GET:
|
||||
response = HttpUtil.get(url, params, new HttpHeader(header), false);
|
||||
break;
|
||||
case POST:
|
||||
if (body == null || "".equals(body)) {
|
||||
response = HttpUtil.post(url, params, new HttpHeader(header), false);
|
||||
} else {
|
||||
response = HttpUtil.post(url, body, new HttpHeader(header));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (response == null) {
|
||||
return null;
|
||||
}
|
||||
String responseBody = response.getBody();
|
||||
Map<String, List<String>> headers = response.getHeaders();
|
||||
return new HttpAuthResponse(response.isSuccess(), responseBody, headers);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,42 @@
|
||||
package com.fujieid.jap.httpapi.util;
|
||||
|
||||
import com.fujieid.jap.core.JapUser;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Convert between json and auth info
|
||||
*
|
||||
* @author zhihai.yu (mvbbb(a)foxmail.com)
|
||||
* @version 1.0.0
|
||||
* @since 1.0.5
|
||||
*/
|
||||
public final class SimpleAuthJsonUtil {
|
||||
|
||||
public static String getJsonStrByParams(Map<String, String> params) {
|
||||
return getJsonStrByJapUserAndParams(null, params);
|
||||
}
|
||||
|
||||
public static String getJsonStrByJapUserAndParams(JapUser japUser, Map<String, String> params) {
|
||||
if (japUser == null && params == null) {
|
||||
return null;
|
||||
}
|
||||
StringBuilder str = new StringBuilder();
|
||||
str.append("{");
|
||||
|
||||
if (japUser != null) {
|
||||
str.append("\"username\":\"").append(japUser.getUsername()).append("\",\"password:\"").append(japUser.getPassword()).append("\",");
|
||||
}
|
||||
|
||||
if (params != null) {
|
||||
params.forEach((key, value) -> str.append("\"").append(key).append("\":\"").append(value).append("\","));
|
||||
}
|
||||
|
||||
if (str.charAt(str.length() - 1) == ',') {
|
||||
str.deleteCharAt(str.length() - 1);
|
||||
}
|
||||
|
||||
str.append("}");
|
||||
return str.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
package com.fujieid.jap.httpapi.util;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* used to convert "Authorization Request Header" and "WWW-Authenticate Response Header" between string and object
|
||||
*
|
||||
* @author zhihai.yu (mvbbb(a)foxmail.com)
|
||||
* @version 1.0.0
|
||||
* @since 1.0.5
|
||||
*/
|
||||
public final class SubjectSerializeUtil {
|
||||
|
||||
/**
|
||||
* Deserialize string to object
|
||||
*
|
||||
* @param str a <code>String</code> to be deserialized
|
||||
* @param clazz The target type to deserialize
|
||||
* @param <T> Actual class type
|
||||
* @return Return an object
|
||||
* @throws NoSuchMethodException no such method
|
||||
* @throws IllegalAccessException illegal access
|
||||
* @throws InvocationTargetException invocation target
|
||||
* @throws InstantiationException instantiation
|
||||
*/
|
||||
public static <T> T deserialize(String str, Class<T> clazz) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
|
||||
str = str.replace("\\", "").replace("\"", "").trim();
|
||||
String[] split = str.split(",");
|
||||
HashMap<String, String> params = new HashMap<>(8);
|
||||
for (String s : split) {
|
||||
String[] param = s.split("=");
|
||||
String paramKey = param[0].trim();
|
||||
String paramValue = param[1].trim();
|
||||
params.put(paramKey, paramValue);
|
||||
}
|
||||
|
||||
Field[] fields = clazz.getDeclaredFields();
|
||||
|
||||
T t = clazz.getDeclaredConstructor().newInstance();
|
||||
|
||||
for (Field field : fields) {
|
||||
field.setAccessible(true);
|
||||
String name = field.getName();
|
||||
field.set(t, params.get(name));
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize object to string
|
||||
*
|
||||
* @param t Objects that need to be serialized
|
||||
* @return return a <code>string</code> after serialization
|
||||
* @throws IllegalAccessException illegal access
|
||||
*/
|
||||
public static String serialize(Object t) throws IllegalAccessException {
|
||||
Class<?> clazz = t.getClass();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Field[] fields = clazz.getDeclaredFields();
|
||||
boolean firstParam = true;
|
||||
for (Field field : fields) {
|
||||
field.setAccessible(true);
|
||||
String paramName = field.getName();
|
||||
String paramVal = ((String) field.get(t));
|
||||
if (Objects.isNull(paramVal)) {
|
||||
continue;
|
||||
}
|
||||
if (!firstParam) {
|
||||
sb.append(",");
|
||||
}
|
||||
firstParam = false;
|
||||
sb.append(paramName).append("=\"").append(paramVal).append("\"");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package com.fujieid.jap.httpapi.util;
|
||||
|
||||
/**
|
||||
* URLUtil
|
||||
*
|
||||
* @author zhihai.yu (mvbbb(a)foxmail.com)
|
||||
* @version 1.0.0
|
||||
* @since 1.0.5
|
||||
*/
|
||||
public class URLUtil {
|
||||
|
||||
private static final String HTTPS_PREFIX = "https://";
|
||||
private static final String HTTP_PREFIX = "http://";
|
||||
|
||||
/**
|
||||
* Get relative uri from uri.
|
||||
* for example:
|
||||
*
|
||||
* <code>
|
||||
* https://www.justauth.plus return to www.justauth.plus
|
||||
* </code>
|
||||
*
|
||||
* @param uri URI with protocol. For example: https://www.justauth.plus
|
||||
* @return Return only the domain name part in the uri
|
||||
*/
|
||||
public static String getRelativeUri(String uri) {
|
||||
if (uri == null) {
|
||||
return null;
|
||||
}
|
||||
String relativeUri = null;
|
||||
if (uri.startsWith(HTTPS_PREFIX)) {
|
||||
relativeUri = uri.replaceFirst(HTTPS_PREFIX, "");
|
||||
} else if (uri.startsWith(HTTP_PREFIX)) {
|
||||
relativeUri = uri.replaceFirst(HTTP_PREFIX, "");
|
||||
} else {
|
||||
relativeUri = uri;
|
||||
}
|
||||
relativeUri = relativeUri.substring(relativeUri.indexOf('/'));
|
||||
return relativeUri;
|
||||
}
|
||||
}
|
67
jap-ids-web/README.md
Normal file
67
jap-ids-web/README.md
Normal file
@ -0,0 +1,67 @@
|
||||
> 本项目主要为了配合 `jap-ids` 使用,内置了 `IdsAccessTokenFilter`(Access Token 验权过滤器) 和 `IdsUserStatusFilter`(用户登录状态过滤器)
|
||||
> 如果不需要该项目中的过滤器,开发者可以自己实现。
|
||||
|
||||
完整示例代码参考:[https://gitee.com/fujieid/jap-ids-demo](https://gitee.com/fujieid/jap-ids-demo)
|
||||
|
||||
|
||||
## 配置过滤器
|
||||
|
||||
`jap-ids` 默认提供了两类过滤器:
|
||||
- Access Token 验权过滤器
|
||||
- 用户登录状态过滤器
|
||||
|
||||
以本项目为例,配置以下两个过滤器:
|
||||
|
||||
### Access Token 验权过滤器
|
||||
```java
|
||||
@Bean
|
||||
public FilterRegistrationBean<IdsAccessTokenFilter> registeraccessTokenFilter() {
|
||||
FilterRegistrationBean<IdsAccessTokenFilter> registration = new FilterRegistrationBean<>();
|
||||
registration.setFilter(new IdsAccessTokenFilter());
|
||||
registration.addUrlPatterns("/*");
|
||||
registration.addInitParameter("ignoreUrl",
|
||||
"/," +
|
||||
"/oauth/login," +
|
||||
"/oauth/error," +
|
||||
"/oauth/confirm," +
|
||||
"/oauth/authorize," +
|
||||
"/oauth/token," +
|
||||
"/oauth/check_session," +
|
||||
"/oauth/registration," +
|
||||
"/.well-known/jwks.json," +
|
||||
"/.well-known/openid-configuration"
|
||||
);
|
||||
registration.setName("IdsAccessTokenFilter");
|
||||
registration.setOrder(1);
|
||||
return registration;
|
||||
}
|
||||
```
|
||||
|
||||
### 用户登录状态过滤器
|
||||
```java
|
||||
@Bean
|
||||
public FilterRegistrationBean<IdsUserStatusFilter> registerUserStatusFilter() {
|
||||
FilterRegistrationBean<IdsUserStatusFilter> registration = new FilterRegistrationBean<>();
|
||||
registration.setFilter(new IdsUserStatusFilter());
|
||||
registration.addUrlPatterns("/*");
|
||||
registration.addInitParameter("ignoreUrl",
|
||||
"/," +
|
||||
"/oauth/login," +
|
||||
"/oauth/error," +
|
||||
"/oauth/confirm," +
|
||||
"/oauth/authorize," +
|
||||
"/oauth/token," +
|
||||
"/oauth/check_session," +
|
||||
"/oauth/registration," +
|
||||
"/.well-known/jwks.json," +
|
||||
"/.well-known/openid-configuration"
|
||||
);
|
||||
registration.setName("IdsUserStatusFilter");
|
||||
registration.setOrder(1);
|
||||
return registration;
|
||||
}
|
||||
```
|
||||
|
||||
## 总结
|
||||
|
||||
基于以上步骤, 就可快速搭建起来一套本地化的 OAuth2.0 服务。更多功能,请参考 [帮助文档](https://justauth.plus/)
|
22
jap-ids-web/pom.xml
Normal file
22
jap-ids-web/pom.xml
Normal file
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>com.fujieid</groupId>
|
||||
<artifactId>jap</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>jap-ids-web</artifactId>
|
||||
<name>jap-ids-web</name>
|
||||
<description>jap-ids-web</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.fujieid</groupId>
|
||||
<artifactId>jap-ids</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@ -13,17 +13,15 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fujieid.jap.ids.filter;
|
||||
package com.fujieid.jap.web.filter;
|
||||
|
||||
import cn.hutool.log.Log;
|
||||
import cn.hutool.log.LogFactory;
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.http.JapHttpResponse;
|
||||
import com.fujieid.jap.ids.JapIds;
|
||||
import com.fujieid.jap.ids.config.IdsConfig;
|
||||
import com.fujieid.jap.ids.pipeline.IdsPipeline;
|
||||
import com.xkcoding.json.util.StringUtil;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@ -37,7 +35,6 @@ import java.util.List;
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class AbstractIdsFilter {
|
||||
protected static final Log log = LogFactory.get();
|
||||
protected final List<String> ignoreUrls = new ArrayList<>();
|
||||
|
||||
/**
|
||||
@ -111,8 +108,8 @@ public class AbstractIdsFilter {
|
||||
if (null == idsFilterErrorPipeline) {
|
||||
idsFilterErrorPipeline = new IdsPipeline<Object>() {
|
||||
@Override
|
||||
public void errorHandle(ServletRequest servletRequest, ServletResponse servletResponse, Throwable throwable) {
|
||||
IdsPipeline.super.errorHandle(servletRequest, servletResponse, throwable);
|
||||
public void errorHandle(JapHttpRequest request, JapHttpResponse response, Throwable throwable) {
|
||||
IdsPipeline.super.errorHandle(request, response, throwable);
|
||||
}
|
||||
};
|
||||
}
|
@ -13,16 +13,19 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fujieid.jap.ids.filter;
|
||||
package com.fujieid.jap.web.filter;
|
||||
|
||||
import cn.hutool.log.Log;
|
||||
import cn.hutool.log.LogFactory;
|
||||
import com.fujieid.jap.http.jakarta.JakartaRequestAdapter;
|
||||
import com.fujieid.jap.http.jakarta.JakartaResponseAdapter;
|
||||
import com.fujieid.jap.ids.JapIds;
|
||||
import com.fujieid.jap.ids.pipeline.IdsPipeline;
|
||||
import com.fujieid.jap.ids.util.TokenUtil;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
@ -47,12 +50,14 @@ public class IdsAccessTokenFilter extends AbstractIdsFilter implements Filter {
|
||||
return;
|
||||
}
|
||||
log.debug("{} - {}", request.getMethod(), request.getRequestURI());
|
||||
String accessToken = TokenUtil.getAccessToken(request);
|
||||
String accessToken = TokenUtil.getAccessToken(new JakartaRequestAdapter(request));
|
||||
try {
|
||||
TokenUtil.validateAccessToken(accessToken);
|
||||
filterChain.doFilter(servletRequest, servletResponse);
|
||||
} catch (Exception e) {
|
||||
this.getFilterErrorPipeline(idsFilterErrorPipeline).errorHandle(servletRequest, servletResponse, e);
|
||||
this.getFilterErrorPipeline(idsFilterErrorPipeline)
|
||||
.errorHandle(new JakartaRequestAdapter((HttpServletRequest) servletRequest),
|
||||
new JakartaResponseAdapter((HttpServletResponse) servletResponse), e);
|
||||
}
|
||||
}
|
||||
|
@ -13,8 +13,10 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fujieid.jap.ids.filter;
|
||||
package com.fujieid.jap.web.filter;
|
||||
|
||||
import com.fujieid.jap.http.jakarta.JakartaRequestAdapter;
|
||||
import com.fujieid.jap.http.jakarta.JakartaResponseAdapter;
|
||||
import com.fujieid.jap.ids.JapIds;
|
||||
import com.fujieid.jap.ids.exception.IdsException;
|
||||
import com.fujieid.jap.ids.model.enums.ErrorResponse;
|
||||
@ -22,6 +24,7 @@ import com.fujieid.jap.ids.pipeline.IdsPipeline;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
@ -36,17 +39,17 @@ public class IdsUserStatusFilter extends AbstractIdsFilter implements Filter {
|
||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
|
||||
IdsPipeline<Object> idsFilterErrorPipeline = JapIds.getContext().getFilterPipeline();
|
||||
HttpServletRequest request = (HttpServletRequest) servletRequest;
|
||||
|
||||
boolean ignored = this.isIgnoredServletPath(request);
|
||||
if (ignored) {
|
||||
filterChain.doFilter(servletRequest, servletResponse);
|
||||
return;
|
||||
}
|
||||
if (JapIds.isAuthenticated(request)) {
|
||||
if (JapIds.isAuthenticated(new JakartaRequestAdapter(request))) {
|
||||
filterChain.doFilter(servletRequest, servletResponse);
|
||||
return;
|
||||
}
|
||||
this.getFilterErrorPipeline(idsFilterErrorPipeline).errorHandle(servletRequest, servletResponse,
|
||||
this.getFilterErrorPipeline(idsFilterErrorPipeline).errorHandle(new JakartaRequestAdapter((HttpServletRequest) servletRequest),
|
||||
new JakartaResponseAdapter((HttpServletResponse) servletResponse),
|
||||
new IdsException(ErrorResponse.INVALID_USER_STATUS));
|
||||
}
|
||||
|
@ -20,4 +20,4 @@
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
package com.fujieid.jap.ids.filter;
|
||||
package com.fujieid.jap.web.filter;
|
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/**
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
package com.fujieid.jap.web;
|
@ -16,6 +16,7 @@
|
||||
package com.fujieid.jap.ids;
|
||||
|
||||
import com.fujieid.jap.core.spi.JapServiceLoader;
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.ids.config.IdsConfig;
|
||||
import com.fujieid.jap.ids.context.IdsContext;
|
||||
import com.fujieid.jap.ids.exception.IdsException;
|
||||
@ -25,7 +26,6 @@ import com.fujieid.jap.ids.pipeline.IdsLogoutPipeline;
|
||||
import com.fujieid.jap.ids.pipeline.IdsSignInPipeline;
|
||||
import com.fujieid.jap.ids.service.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
@ -90,21 +90,21 @@ public class JapIds implements Serializable {
|
||||
return context;
|
||||
}
|
||||
|
||||
public static boolean isAuthenticated(HttpServletRequest request) {
|
||||
public static boolean isAuthenticated(JapHttpRequest request) {
|
||||
return null != getUserInfo(request);
|
||||
}
|
||||
|
||||
public static void saveUserInfo(UserInfo userInfo, HttpServletRequest request) {
|
||||
public static void saveUserInfo(UserInfo userInfo, JapHttpRequest request) {
|
||||
IdsContext context = getContext();
|
||||
context.getUserStoreService().save(userInfo, request);
|
||||
}
|
||||
|
||||
public static UserInfo getUserInfo(HttpServletRequest request) {
|
||||
public static UserInfo getUserInfo(JapHttpRequest request) {
|
||||
IdsContext context = getContext();
|
||||
return context.getUserStoreService().get(request);
|
||||
}
|
||||
|
||||
public static void removeUserInfo(HttpServletRequest request) {
|
||||
public static void removeUserInfo(JapHttpRequest request) {
|
||||
IdsContext context = getContext();
|
||||
context.getUserStoreService().remove(request);
|
||||
}
|
||||
|
@ -15,14 +15,13 @@
|
||||
*/
|
||||
package com.fujieid.jap.ids.endpoint;
|
||||
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.http.JapHttpResponse;
|
||||
import com.fujieid.jap.ids.model.UserInfo;
|
||||
import com.fujieid.jap.ids.pipeline.IdsPipeline;
|
||||
import com.fujieid.jap.ids.service.Oauth2Service;
|
||||
import com.fujieid.jap.ids.service.Oauth2ServiceImpl;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
/**
|
||||
* Abstract classes common to various endpoints
|
||||
*
|
||||
@ -41,13 +40,13 @@ public abstract class AbstractEndpoint {
|
||||
if (null == idsSigninPipeline) {
|
||||
idsSigninPipeline = new IdsPipeline<UserInfo>() {
|
||||
@Override
|
||||
public boolean preHandle(ServletRequest servletRequest, ServletResponse servletResponse) {
|
||||
return IdsPipeline.super.preHandle(servletRequest, servletResponse);
|
||||
public boolean preHandle(JapHttpRequest httpRequest, JapHttpResponse httpResponse) {
|
||||
return IdsPipeline.super.preHandle(httpRequest, httpResponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserInfo postHandle(ServletRequest servletRequest, ServletResponse servletResponse) {
|
||||
return IdsPipeline.super.postHandle(servletRequest, servletResponse);
|
||||
public UserInfo postHandle(JapHttpRequest httpRequest, JapHttpResponse httpResponse) {
|
||||
return IdsPipeline.super.postHandle(httpRequest, httpResponse);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.fujieid.jap.ids.endpoint;
|
||||
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.http.JapHttpResponse;
|
||||
import com.fujieid.jap.ids.JapIds;
|
||||
import com.fujieid.jap.ids.model.ClientDetail;
|
||||
import com.fujieid.jap.ids.model.IdsRequestParam;
|
||||
@ -26,9 +28,8 @@ import com.fujieid.jap.ids.util.EndpointUtil;
|
||||
import com.fujieid.jap.ids.util.OauthUtil;
|
||||
import com.fujieid.jap.ids.util.ObjectUtils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
@ -47,10 +48,11 @@ public class ApprovalEndpoint extends AbstractEndpoint {
|
||||
* @param response current HTTP response
|
||||
* @throws IOException IOException
|
||||
*/
|
||||
public void showConfirmPage(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
public void showConfirmPage(JapHttpRequest request, JapHttpResponse response) throws IOException {
|
||||
final String approvalContent = createConfirmPageHtml(request);
|
||||
response.setContentType("text/html;charset=UTF-8");
|
||||
response.getWriter().append(approvalContent);
|
||||
response.setContentLength(approvalContent.getBytes(StandardCharsets.UTF_8).length);
|
||||
response.write(approvalContent);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -59,7 +61,7 @@ public class ApprovalEndpoint extends AbstractEndpoint {
|
||||
* @param request HttpServletRequest
|
||||
* @return IdsResponse
|
||||
*/
|
||||
public IdsResponse<String, Map<String, Object>> getAuthClientInfo(HttpServletRequest request) {
|
||||
public IdsResponse<String, Map<String, Object>> getAuthClientInfo(JapHttpRequest request) {
|
||||
IdsRequestParam param = IdsRequestParamProvider.parseRequest(request);
|
||||
ClientDetail clientDetail = JapIds.getContext().getClientDetailService().getByClientId(param.getClientId());
|
||||
OauthUtil.validClientDetail(clientDetail);
|
||||
@ -80,7 +82,7 @@ public class ApprovalEndpoint extends AbstractEndpoint {
|
||||
* @param request current HTTP request
|
||||
* @return Confirm the html of the authorization page
|
||||
*/
|
||||
private String createConfirmPageHtml(HttpServletRequest request) {
|
||||
private String createConfirmPageHtml(JapHttpRequest request) {
|
||||
IdsRequestParam param = IdsRequestParamProvider.parseRequest(request);
|
||||
String clientId = param.getClientId();
|
||||
ClientDetail clientDetail = JapIds.getContext().getClientDetailService().getByClientId(clientId);
|
||||
@ -132,7 +134,7 @@ public class ApprovalEndpoint extends AbstractEndpoint {
|
||||
* @param request current HTTP request
|
||||
* @return the scope list of the authorization confirmation page
|
||||
*/
|
||||
private String createScopes(IdsRequestParam param, HttpServletRequest request) {
|
||||
private String createScopes(IdsRequestParam param, JapHttpRequest request) {
|
||||
StringBuilder builder = new StringBuilder("<ul style=\"list-style: none;padding-inline-start: 20px;\">");
|
||||
List<Map<String, Object>> scopeInfo = getScopeInfo(param);
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
package com.fujieid.jap.ids.endpoint;
|
||||
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.ids.JapIds;
|
||||
import com.fujieid.jap.ids.exception.InvalidScopeException;
|
||||
import com.fujieid.jap.ids.model.ClientDetail;
|
||||
@ -30,7 +31,6 @@ import com.fujieid.jap.ids.util.EndpointUtil;
|
||||
import com.fujieid.jap.ids.util.OauthUtil;
|
||||
import com.xkcoding.json.util.StringUtil;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
@ -59,7 +59,7 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
|
||||
* @return Callback url or authorization url
|
||||
* @throws IOException IOException
|
||||
*/
|
||||
public IdsResponse<String, String> authorize(HttpServletRequest request) throws IOException {
|
||||
public IdsResponse<String, String> authorize(JapHttpRequest request) throws IOException {
|
||||
IdsRequestParam param = IdsRequestParamProvider.parseRequest(request);
|
||||
|
||||
ClientDetail clientDetail = JapIds.getContext().getClientDetailService().getByClientId(param.getClientId());
|
||||
@ -85,7 +85,7 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
|
||||
* @param request current HTTP request
|
||||
* @return Return the callback url (with parameters such as code)
|
||||
*/
|
||||
public IdsResponse<String, String> agree(HttpServletRequest request) {
|
||||
public IdsResponse<String, String> agree(JapHttpRequest request) {
|
||||
IdsRequestParam param = IdsRequestParamProvider.parseRequest(request);
|
||||
|
||||
// The scope checked by the user may be inconsistent with the scope passed in the current HTTP request
|
||||
|
@ -15,11 +15,10 @@
|
||||
*/
|
||||
package com.fujieid.jap.ids.endpoint;
|
||||
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.ids.model.OidcDiscoveryDto;
|
||||
import com.fujieid.jap.ids.oidc.OidcUtil;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* OpenID Provider Endpoint
|
||||
*
|
||||
@ -46,7 +45,7 @@ public class DiscoveryEndpoint extends AbstractEndpoint {
|
||||
* @see <a href="https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata" target="_blank">OpenID Provider Metadata</a>
|
||||
* @see <a href="https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationRequest">OpenID Provider Configuration Response</a>
|
||||
*/
|
||||
public OidcDiscoveryDto getOidcDiscoveryInfo(HttpServletRequest request) {
|
||||
public OidcDiscoveryDto getOidcDiscoveryInfo(JapHttpRequest request) {
|
||||
return OidcUtil.getOidcDiscoveryInfo(request);
|
||||
}
|
||||
|
||||
|
@ -15,12 +15,12 @@
|
||||
*/
|
||||
package com.fujieid.jap.ids.endpoint;
|
||||
|
||||
import com.fujieid.jap.core.util.RequestUtil;
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.http.JapHttpResponse;
|
||||
import com.fujieid.jap.http.RequestUtil;
|
||||
import com.fujieid.jap.ids.model.enums.ErrorResponse;
|
||||
import com.xkcoding.json.util.StringUtil;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
@ -51,12 +51,12 @@ public class ErrorEndpoint extends AbstractEndpoint {
|
||||
* @param response current HTTP response
|
||||
* @throws IOException IOException
|
||||
*/
|
||||
public void showErrorPage(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
public void showErrorPage(JapHttpRequest request, JapHttpResponse response) throws IOException {
|
||||
ErrorResponse errorResponse = ErrorResponse.getByError(RequestUtil.getParam("error", request));
|
||||
String errorPageHtml = createErrorPageHtml(errorResponse.getError(), errorResponse.getErrorDescription());
|
||||
response.setContentType("text/html;charset=UTF-8");
|
||||
response.setContentLength(errorPageHtml.getBytes(StandardCharsets.UTF_8).length);
|
||||
response.getWriter().write(errorPageHtml);
|
||||
response.write(errorPageHtml);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -67,11 +67,11 @@ public class ErrorEndpoint extends AbstractEndpoint {
|
||||
* @param response current HTTP response
|
||||
* @throws IOException IOException
|
||||
*/
|
||||
public void showErrorPage(String error, String errorDescription, HttpServletResponse response) throws IOException {
|
||||
public void showErrorPage(String error, String errorDescription, JapHttpResponse response) throws IOException {
|
||||
String errorPageHtml = createErrorPageHtml(error, errorDescription);
|
||||
response.setContentType("text/html;charset=UTF-8");
|
||||
response.setContentLength(errorPageHtml.getBytes(StandardCharsets.UTF_8).length);
|
||||
response.getWriter().write(errorPageHtml);
|
||||
response.write(errorPageHtml);
|
||||
}
|
||||
|
||||
|
||||
|
@ -17,6 +17,8 @@ package com.fujieid.jap.ids.endpoint;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.http.JapHttpResponse;
|
||||
import com.fujieid.jap.ids.JapIds;
|
||||
import com.fujieid.jap.ids.exception.IdsException;
|
||||
import com.fujieid.jap.ids.model.ClientDetail;
|
||||
@ -30,10 +32,6 @@ import com.fujieid.jap.ids.util.EndpointUtil;
|
||||
import com.fujieid.jap.ids.util.OauthUtil;
|
||||
import com.fujieid.jap.ids.util.ObjectUtils;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
@ -53,14 +51,14 @@ public class LoginEndpoint extends AbstractEndpoint {
|
||||
* @param response current HTTP response
|
||||
* @throws IOException IOException
|
||||
*/
|
||||
public void showLoginPage(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
public void showLoginPage(JapHttpRequest request, JapHttpResponse response) throws IOException {
|
||||
String loginPageHtml = generateLoginPageHtml(request);
|
||||
response.setContentType("text/html;charset=UTF-8");
|
||||
response.setContentLength(loginPageHtml.getBytes(StandardCharsets.UTF_8).length);
|
||||
response.getWriter().write(loginPageHtml);
|
||||
response.write(loginPageHtml);
|
||||
}
|
||||
|
||||
private String generateLoginPageHtml(HttpServletRequest request) {
|
||||
private String generateLoginPageHtml(JapHttpRequest request) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("<!DOCTYPE html>\n"
|
||||
+ "<html lang=\"en\">\n"
|
||||
@ -98,19 +96,18 @@ public class LoginEndpoint extends AbstractEndpoint {
|
||||
/**
|
||||
* Login with account password
|
||||
*
|
||||
* @param servletRequest current HTTP request
|
||||
* @param servletResponse current HTTP response
|
||||
* @param request current HTTP request
|
||||
* @param response current HTTP response
|
||||
* @return Confirm authorization page
|
||||
*/
|
||||
public IdsResponse<String, String> signin(ServletRequest servletRequest, ServletResponse servletResponse) {
|
||||
HttpServletRequest request = (HttpServletRequest) servletRequest;
|
||||
public IdsResponse<String, String> signin(JapHttpRequest request, JapHttpResponse response) {
|
||||
IdsPipeline<UserInfo> idsSigninPipeline = JapIds.getContext().getSigninPipeline();
|
||||
idsSigninPipeline = this.getUserInfoIdsPipeline(idsSigninPipeline);
|
||||
if (!idsSigninPipeline.preHandle(request, servletResponse)) {
|
||||
if (!idsSigninPipeline.preHandle(request, response)) {
|
||||
throw new IdsException("IdsSigninPipeline<UserInfo>.preHandle returns false, the process is blocked.");
|
||||
}
|
||||
IdsRequestParam param = IdsRequestParamProvider.parseRequest(request);
|
||||
UserInfo userInfo = idsSigninPipeline.postHandle(request, servletResponse);
|
||||
UserInfo userInfo = idsSigninPipeline.postHandle(request, response);
|
||||
if (null == userInfo) {
|
||||
String username = param.getUsername();
|
||||
String password = param.getPassword();
|
||||
|
@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.fujieid.jap.ids.endpoint;
|
||||
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.http.JapHttpResponse;
|
||||
import com.fujieid.jap.ids.JapIds;
|
||||
import com.fujieid.jap.ids.exception.IdsException;
|
||||
import com.fujieid.jap.ids.model.IdsResponse;
|
||||
@ -22,9 +24,6 @@ import com.fujieid.jap.ids.model.UserInfo;
|
||||
import com.fujieid.jap.ids.pipeline.IdsPipeline;
|
||||
import com.fujieid.jap.ids.util.EndpointUtil;
|
||||
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* Logout Endpoint
|
||||
*
|
||||
@ -34,7 +33,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||
*/
|
||||
public class LogoutEndpoint extends AbstractEndpoint {
|
||||
|
||||
public IdsResponse<String, String> logout(HttpServletRequest request, ServletResponse response) {
|
||||
public IdsResponse<String, String> logout(JapHttpRequest request, JapHttpResponse response) {
|
||||
IdsPipeline<UserInfo> logoutPipeline = JapIds.getContext().getLogoutPipeline();
|
||||
logoutPipeline = this.getUserInfoIdsPipeline(logoutPipeline);
|
||||
if (!logoutPipeline.preHandle(request, response)) {
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.fujieid.jap.ids.endpoint;
|
||||
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.ids.exception.UnsupportedGrantTypeException;
|
||||
import com.fujieid.jap.ids.model.IdsRequestParam;
|
||||
import com.fujieid.jap.ids.model.IdsResponse;
|
||||
@ -25,8 +26,6 @@ import com.fujieid.jap.ids.provider.IdsTokenProvider;
|
||||
import com.fujieid.jap.ids.util.TokenUtil;
|
||||
import com.xkcoding.json.util.StringUtil;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* Token Endpoint. According to the request parameters, to obtain different types of access tokens, refer to:
|
||||
* <p>
|
||||
@ -44,7 +43,7 @@ public class TokenEndpoint extends AbstractEndpoint {
|
||||
|
||||
private final IdsTokenProvider idsTokenProvider = new IdsTokenProvider(oauth2Service);
|
||||
|
||||
public IdsResponse<String, Object> getToken(HttpServletRequest request) {
|
||||
public IdsResponse<String, Object> getToken(JapHttpRequest request) {
|
||||
IdsRequestParam param = IdsRequestParamProvider.parseRequest(request);
|
||||
|
||||
if (StringUtil.isEmpty(param.getGrantType())) {
|
||||
@ -65,7 +64,7 @@ public class TokenEndpoint extends AbstractEndpoint {
|
||||
throw new UnsupportedGrantTypeException(ErrorResponse.UNSUPPORTED_GRANT_TYPE);
|
||||
}
|
||||
|
||||
public IdsResponse<String, Object> revokeToken(HttpServletRequest request) {
|
||||
public IdsResponse<String, Object> revokeToken(JapHttpRequest request) {
|
||||
TokenUtil.invalidateToken(request);
|
||||
return new IdsResponse<>();
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.fujieid.jap.ids.endpoint;
|
||||
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.ids.JapIds;
|
||||
import com.fujieid.jap.ids.exception.IdsException;
|
||||
import com.fujieid.jap.ids.exception.InvalidTokenException;
|
||||
@ -27,7 +28,6 @@ import com.fujieid.jap.ids.util.OauthUtil;
|
||||
import com.fujieid.jap.ids.util.TokenUtil;
|
||||
import com.xkcoding.json.JsonUtil;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@ -51,7 +51,7 @@ public class UserInfoEndpoint extends AbstractEndpoint {
|
||||
* @see <a href="https://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse" target="_blank">5.3.2. Successful UserInfo Response</a>
|
||||
* @see <a href="https://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims" target="_blank">5.4. Requesting Claims using Scope Values</a>
|
||||
*/
|
||||
public IdsResponse<String, Object> getCurrentUserInfo(HttpServletRequest request) {
|
||||
public IdsResponse<String, Object> getCurrentUserInfo(JapHttpRequest request) {
|
||||
|
||||
String accessTokenStr = TokenUtil.getAccessToken(request);
|
||||
|
||||
|
@ -14,7 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
/**
|
||||
* ids The service endpoint that needs to be provided externally
|
||||
* API methods that need to be provided externally,
|
||||
* <p>
|
||||
* such as: obtaining authorization, obtaining AccessToken, refreshing AccessToken, obtaining IDS service discovery configuration, etc.
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0.0
|
||||
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/**
|
||||
* enum in ids
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
package com.fujieid.jap.ids.model.enums;
|
@ -18,6 +18,7 @@ package com.fujieid.jap.ids.oidc;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.ids.JapIds;
|
||||
import com.fujieid.jap.ids.config.IdsConfig;
|
||||
import com.fujieid.jap.ids.model.IdsConsts;
|
||||
@ -32,7 +33,6 @@ import org.jose4j.jwk.JsonWebKey;
|
||||
import org.jose4j.jwk.JsonWebKeySet;
|
||||
import org.jose4j.jwt.ReservedClaimNames;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -43,14 +43,14 @@ import java.util.stream.Collectors;
|
||||
*/
|
||||
public class OidcUtil {
|
||||
|
||||
public static OidcDiscoveryDto getOidcDiscoveryInfo(HttpServletRequest request) {
|
||||
public static OidcDiscoveryDto getOidcDiscoveryInfo(JapHttpRequest request) {
|
||||
|
||||
IdsConfig config = JapIds.getIdsConfig();
|
||||
List<String> scopes = IdsScopeProvider.getScopeCodes();
|
||||
|
||||
String issuer = EndpointUtil.getIssuer(request);
|
||||
|
||||
Map<String, Object> model = new HashMap<>();
|
||||
Map<String, Object> model = new HashMap<>(33);
|
||||
model.put("issuer", issuer);
|
||||
model.put("authorization_endpoint", EndpointUtil.getAuthorizeUrl(request));
|
||||
model.put("token_endpoint", EndpointUtil.getTokenUrl(request));
|
||||
@ -80,14 +80,14 @@ public class OidcUtil {
|
||||
}
|
||||
|
||||
model.put("request_object_signing_alg_values_supported", Arrays.asList(
|
||||
"none",
|
||||
"RS256",
|
||||
"ES256"
|
||||
"none",
|
||||
"RS256",
|
||||
"ES256"
|
||||
)
|
||||
);
|
||||
model.put("userinfo_signing_alg_values_supported", Arrays.asList(
|
||||
"RS256",
|
||||
"ES256"
|
||||
"RS256",
|
||||
"ES256"
|
||||
)
|
||||
);
|
||||
model.put("request_parameter_supported", true);
|
||||
@ -95,8 +95,8 @@ public class OidcUtil {
|
||||
model.put("require_request_uri_registration", false);
|
||||
model.put("claims_parameter_supported", true);
|
||||
model.put("id_token_signing_alg_values_supported", Arrays.asList(
|
||||
"RS256",
|
||||
"ES256"
|
||||
"RS256",
|
||||
"ES256"
|
||||
)
|
||||
);
|
||||
model.put("subject_types_supported", Collections.singletonList("public"));
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
/**
|
||||
* Support openid connect
|
||||
* Support for openid connect, including Id Token and OIDC tools
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0.0
|
||||
|
@ -15,13 +15,14 @@
|
||||
*/
|
||||
package com.fujieid.jap.ids.pipeline;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.http.JapHttpResponse;
|
||||
|
||||
/**
|
||||
* For the filter of jap-ids, a pipeline interface is provided. When an exception occurs in the filter,
|
||||
* <p>
|
||||
* you can use {@link com.fujieid.jap.ids.pipeline.IdsFilterPipeline#errorHandle(ServletRequest, ServletResponse, Throwable)} to handle the exception information .
|
||||
* you can use {@link com.fujieid.jap.ids.pipeline.IdsFilterPipeline#errorHandle(JapHttpRequest, JapHttpResponse, Throwable)} to handle the exception information .
|
||||
* <p>
|
||||
* The data in json format is returned by default:
|
||||
*
|
||||
@ -32,7 +33,7 @@ import javax.servlet.ServletResponse;
|
||||
* }
|
||||
* </code>
|
||||
* <p>
|
||||
* Note: Only need to implement the {@link com.fujieid.jap.ids.pipeline.IdsFilterPipeline#errorHandle(ServletRequest, ServletResponse, Throwable)} method of this interface.
|
||||
* Note: Only need to implement the {@link com.fujieid.jap.ids.pipeline.IdsFilterPipeline#errorHandle(JapHttpRequest, JapHttpResponse, Throwable)} method of this interface.
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0.0
|
||||
@ -42,50 +43,50 @@ public interface IdsFilterPipeline extends IdsPipeline<Object> {
|
||||
/**
|
||||
* Callback when the program is abnormal
|
||||
*
|
||||
* @param servletRequest current HTTP request
|
||||
* @param servletResponse current HTTP response
|
||||
* @param throwable any exception thrown on handler execution, if any.
|
||||
* @param request current HTTP request
|
||||
* @param response current HTTP response
|
||||
* @param throwable any exception thrown on handler execution, if any.
|
||||
*/
|
||||
@Override
|
||||
default void errorHandle(ServletRequest servletRequest, ServletResponse servletResponse, Throwable throwable) {
|
||||
IdsPipeline.super.errorHandle(servletRequest, servletResponse, throwable);
|
||||
default void errorHandle(JapHttpRequest request, JapHttpResponse response, Throwable throwable) {
|
||||
IdsPipeline.super.errorHandle(request, response, throwable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Operations before business process processing, such as initializing resources, etc.
|
||||
*
|
||||
* @param servletRequest current HTTP request
|
||||
* @param servletResponse current HTTP response
|
||||
* @param request current HTTP request
|
||||
* @param response current HTTP response
|
||||
* @return boolean
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
default boolean preHandle(ServletRequest servletRequest, ServletResponse servletResponse) {
|
||||
return IdsPipeline.super.preHandle(servletRequest, servletResponse);
|
||||
default boolean preHandle(JapHttpRequest request, JapHttpResponse response) {
|
||||
return IdsPipeline.super.preHandle(request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Intercept the execution of a handler
|
||||
*
|
||||
* @param servletRequest current HTTP request
|
||||
* @param servletResponse current HTTP response
|
||||
* @param request current HTTP request
|
||||
* @param response current HTTP response
|
||||
* @return Object
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
default Object postHandle(ServletRequest servletRequest, ServletResponse servletResponse) {
|
||||
return IdsPipeline.super.postHandle(servletRequest, servletResponse);
|
||||
default Object postHandle(JapHttpRequest request, JapHttpResponse response) {
|
||||
return IdsPipeline.super.postHandle(request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback after business process processing is completed, such as recycling resources, recording status, etc.
|
||||
*
|
||||
* @param servletRequest current HTTP request
|
||||
* @param servletResponse current HTTP response
|
||||
* @param request current HTTP request
|
||||
* @param response current HTTP response
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
default void afterHandle(ServletRequest servletRequest, ServletResponse servletResponse) {
|
||||
IdsPipeline.super.afterHandle(servletRequest, servletResponse);
|
||||
default void afterHandle(JapHttpRequest request, JapHttpResponse response) {
|
||||
IdsPipeline.super.afterHandle(request, response);
|
||||
}
|
||||
}
|
||||
|
@ -15,13 +15,12 @@
|
||||
*/
|
||||
package com.fujieid.jap.ids.pipeline;
|
||||
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.http.JapHttpResponse;
|
||||
import com.fujieid.jap.ids.exception.IdsException;
|
||||
import com.fujieid.jap.ids.model.IdsResponse;
|
||||
import com.xkcoding.json.JsonUtil;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
@ -41,57 +40,53 @@ public interface IdsPipeline<T> {
|
||||
/**
|
||||
* Callback when the program is abnormal
|
||||
*
|
||||
* @param servletRequest current HTTP request
|
||||
* @param servletResponse current HTTP response
|
||||
* @param throwable any exception thrown on handler execution, if any.
|
||||
* @param request current HTTP request
|
||||
* @param response current HTTP response
|
||||
* @param throwable any exception thrown on handler execution, if any.
|
||||
*/
|
||||
default void errorHandle(ServletRequest servletRequest, ServletResponse servletResponse, Throwable throwable) {
|
||||
IdsResponse<String, Object> response = new IdsResponse<>();
|
||||
default void errorHandle(JapHttpRequest request, JapHttpResponse response, Throwable throwable) {
|
||||
IdsResponse<String, Object> idsResponse = new IdsResponse<>();
|
||||
if (throwable instanceof IdsException) {
|
||||
IdsException idsException = (IdsException) throwable;
|
||||
response.error(idsException.getError())
|
||||
idsResponse.error(idsException.getError())
|
||||
.errorDescription(idsException.getErrorDescription());
|
||||
} else {
|
||||
response.errorDescription(throwable.getMessage());
|
||||
}
|
||||
String errorResponseStr = JsonUtil.toJsonString(response);
|
||||
servletResponse.setContentType("text/html;charset=UTF-8");
|
||||
servletResponse.setContentLength(errorResponseStr.getBytes(StandardCharsets.UTF_8).length);
|
||||
try {
|
||||
servletResponse.getWriter().write(errorResponseStr);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
idsResponse.errorDescription(throwable.getMessage());
|
||||
}
|
||||
String errorResponseStr = JsonUtil.toJsonString(idsResponse);
|
||||
response.setContentType("text/html;charset=UTF-8");
|
||||
response.setContentLength(errorResponseStr.getBytes(StandardCharsets.UTF_8).length);
|
||||
response.write(errorResponseStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Operations before business process processing, such as initializing resources, etc.
|
||||
*
|
||||
* @param servletRequest current HTTP request
|
||||
* @param servletResponse current HTTP response
|
||||
* @param request current HTTP request
|
||||
* @param response current HTTP response
|
||||
* @return boolean
|
||||
*/
|
||||
default boolean preHandle(ServletRequest servletRequest, ServletResponse servletResponse) {
|
||||
default boolean preHandle(JapHttpRequest request, JapHttpResponse response) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Intercept the execution of a handler
|
||||
*
|
||||
* @param servletRequest current HTTP request
|
||||
* @param servletResponse current HTTP response
|
||||
* @param request current HTTP request
|
||||
* @param response current HTTP response
|
||||
* @return Object
|
||||
*/
|
||||
default T postHandle(ServletRequest servletRequest, ServletResponse servletResponse) {
|
||||
default T postHandle(JapHttpRequest request, JapHttpResponse response) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback after business process processing is completed, such as recycling resources, recording status, etc.
|
||||
*
|
||||
* @param servletRequest current HTTP request
|
||||
* @param servletResponse current HTTP response
|
||||
* @param request current HTTP request
|
||||
* @param response current HTTP response
|
||||
*/
|
||||
default void afterHandle(ServletRequest servletRequest, ServletResponse servletResponse) {
|
||||
default void afterHandle(JapHttpRequest request, JapHttpResponse response) {
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
package com.fujieid.jap.ids.provider;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.ids.JapIds;
|
||||
import com.fujieid.jap.ids.config.IdsConfig;
|
||||
import com.fujieid.jap.ids.exception.InvalidRequestException;
|
||||
@ -25,8 +26,6 @@ import com.fujieid.jap.ids.model.IdsRequestParam;
|
||||
import com.fujieid.jap.ids.model.enums.ErrorResponse;
|
||||
import com.fujieid.jap.ids.util.ClientCertificateUtil;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* Parameter parser for oauth request
|
||||
*
|
||||
@ -36,7 +35,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||
*/
|
||||
public class IdsRequestParamProvider {
|
||||
|
||||
public static IdsRequestParam parseRequest(HttpServletRequest request) {
|
||||
public static IdsRequestParam parseRequest(JapHttpRequest request) {
|
||||
if (ObjectUtil.isEmpty(request.getParameterMap())) {
|
||||
throw new InvalidRequestException(ErrorResponse.INVALID_REQUEST);
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ package com.fujieid.jap.ids.provider;
|
||||
|
||||
import cn.hutool.log.Log;
|
||||
import cn.hutool.log.LogFactory;
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.ids.JapIds;
|
||||
import com.fujieid.jap.ids.exception.IdsException;
|
||||
import com.fujieid.jap.ids.model.*;
|
||||
@ -28,8 +29,6 @@ import com.fujieid.jap.ids.util.OauthUtil;
|
||||
import com.fujieid.jap.ids.util.TokenUtil;
|
||||
import com.xkcoding.json.util.StringUtil;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* The token endpoint creates a token, and returns different token information for different authorization types
|
||||
*
|
||||
@ -54,7 +53,7 @@ public class IdsTokenProvider {
|
||||
* @return IdsResponse
|
||||
* @see <a href="https://tools.ietf.org/html/rfc6749#section-4.1" target="_blank">4.1. Authorization Code Grant</a>
|
||||
*/
|
||||
public IdsResponse<String, Object> generateAuthorizationCodeResponse(IdsRequestParam param, HttpServletRequest request) {
|
||||
public IdsResponse<String, Object> generateAuthorizationCodeResponse(IdsRequestParam param, JapHttpRequest request) {
|
||||
AuthCode codeInfo = oauth2Service.validateAndGetAuthrizationCode(param.getGrantType(), param.getCode());
|
||||
|
||||
String scope = codeInfo.getScope();
|
||||
@ -93,7 +92,7 @@ public class IdsTokenProvider {
|
||||
* @return IdsResponse
|
||||
* @see <a href="https://tools.ietf.org/html/rfc6749#section-4.3" target="_blank">4.3. Resource Owner Password Credentials Grant</a>
|
||||
*/
|
||||
public IdsResponse<String, Object> generatePasswordResponse(IdsRequestParam param, HttpServletRequest request) {
|
||||
public IdsResponse<String, Object> generatePasswordResponse(IdsRequestParam param, JapHttpRequest request) {
|
||||
String username = param.getUsername();
|
||||
String password = param.getPassword();
|
||||
String clientId = param.getClientId();
|
||||
@ -135,7 +134,7 @@ public class IdsTokenProvider {
|
||||
* @return IdsResponse
|
||||
* @see <a href="https://tools.ietf.org/html/rfc6749#section-4.4" target="_blank">4.4. Client Credentials Grant</a>
|
||||
*/
|
||||
public IdsResponse<String, Object> generateClientCredentialsResponse(IdsRequestParam param, HttpServletRequest request) {
|
||||
public IdsResponse<String, Object> generateClientCredentialsResponse(IdsRequestParam param, JapHttpRequest request) {
|
||||
String clientId = param.getClientId();
|
||||
|
||||
ClientDetail clientDetail = JapIds.getContext().getClientDetailService().getByClientId(clientId);
|
||||
@ -170,7 +169,7 @@ public class IdsTokenProvider {
|
||||
* @return IdsResponse
|
||||
* @see <a href="https://tools.ietf.org/html/rfc6749#section-6" target="_blank">6. Refreshing an Access Token</a>
|
||||
*/
|
||||
public IdsResponse<String, Object> generateRefreshTokenResponse(IdsRequestParam param, HttpServletRequest request) {
|
||||
public IdsResponse<String, Object> generateRefreshTokenResponse(IdsRequestParam param, JapHttpRequest request) {
|
||||
TokenUtil.validateRefreshToken(param.getRefreshToken());
|
||||
|
||||
AccessToken token = TokenUtil.getByRefreshToken(param.getRefreshToken());
|
||||
|
@ -15,10 +15,9 @@
|
||||
*/
|
||||
package com.fujieid.jap.ids.service;
|
||||
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.ids.model.UserInfo;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* When the user logs in, store and operate the user's login information
|
||||
*
|
||||
@ -29,14 +28,14 @@ import javax.servlet.http.HttpServletRequest;
|
||||
public interface IdsUserStoreService {
|
||||
|
||||
/**
|
||||
* Save user data, and store user information in {@link javax.servlet.http.HttpSession} by default.
|
||||
* Save user data, and store user information in {@link com.fujieid.jap.http.JapHttpSession} by default.
|
||||
* <p>
|
||||
* Developers can implement this method to save user information in other media, such as cache, database, etc.
|
||||
*
|
||||
* @param userInfo User information after login
|
||||
* @param request current HTTP request
|
||||
*/
|
||||
void save(UserInfo userInfo, HttpServletRequest request);
|
||||
void save(UserInfo userInfo, JapHttpRequest request);
|
||||
|
||||
/**
|
||||
* Get logged-in user information
|
||||
@ -44,12 +43,12 @@ public interface IdsUserStoreService {
|
||||
* @param request current HTTP request
|
||||
* @return UserInfo
|
||||
*/
|
||||
UserInfo get(HttpServletRequest request);
|
||||
UserInfo get(JapHttpRequest request);
|
||||
|
||||
/**
|
||||
* Delete logged-in user information
|
||||
*
|
||||
* @param request current HTTP request
|
||||
*/
|
||||
void remove(HttpServletRequest request);
|
||||
void remove(JapHttpRequest request);
|
||||
}
|
||||
|
@ -15,12 +15,10 @@
|
||||
*/
|
||||
package com.fujieid.jap.ids.service;
|
||||
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.ids.model.IdsConsts;
|
||||
import com.fujieid.jap.ids.model.UserInfo;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
/**
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0.0
|
||||
@ -29,7 +27,7 @@ import javax.servlet.http.HttpSession;
|
||||
public class IdsUserStoreServiceImpl implements IdsUserStoreService {
|
||||
|
||||
/**
|
||||
* Save user data, and store user information in {@link HttpSession} by default.
|
||||
* Save user data, and store user information in {@link com.fujieid.jap.http.JapHttpSession} by default.
|
||||
* <p>
|
||||
* Developers can implement this method to save user information in other media, such as cache, database, etc.
|
||||
*
|
||||
@ -37,7 +35,7 @@ public class IdsUserStoreServiceImpl implements IdsUserStoreService {
|
||||
* @param request current HTTP request
|
||||
*/
|
||||
@Override
|
||||
public void save(UserInfo userInfo, HttpServletRequest request) {
|
||||
public void save(UserInfo userInfo, JapHttpRequest request) {
|
||||
request.getSession().setAttribute(IdsConsts.OAUTH_USERINFO_CACHE_KEY, userInfo);
|
||||
}
|
||||
|
||||
@ -48,7 +46,7 @@ public class IdsUserStoreServiceImpl implements IdsUserStoreService {
|
||||
* @return UserInfo
|
||||
*/
|
||||
@Override
|
||||
public UserInfo get(HttpServletRequest request) {
|
||||
public UserInfo get(JapHttpRequest request) {
|
||||
return (UserInfo) request.getSession().getAttribute(IdsConsts.OAUTH_USERINFO_CACHE_KEY);
|
||||
}
|
||||
|
||||
@ -58,7 +56,7 @@ public class IdsUserStoreServiceImpl implements IdsUserStoreService {
|
||||
* @param request current HTTP request
|
||||
*/
|
||||
@Override
|
||||
public void remove(HttpServletRequest request) {
|
||||
public void remove(JapHttpRequest request) {
|
||||
request.getSession().removeAttribute(IdsConsts.OAUTH_USERINFO_CACHE_KEY);
|
||||
}
|
||||
}
|
||||
|
@ -16,14 +16,14 @@
|
||||
package com.fujieid.jap.ids.util;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.fujieid.jap.core.util.RequestUtil;
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.http.RequestUtil;
|
||||
import com.fujieid.jap.ids.JapIds;
|
||||
import com.fujieid.jap.ids.model.ClientCertificate;
|
||||
import com.fujieid.jap.ids.model.IdsConsts;
|
||||
import com.fujieid.jap.ids.model.enums.ClientSecretAuthMethod;
|
||||
import com.xkcoding.json.util.StringUtil;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@ -36,7 +36,7 @@ import java.util.List;
|
||||
*/
|
||||
public class ClientCertificateUtil {
|
||||
|
||||
public static ClientCertificate getClientCertificate(HttpServletRequest request) {
|
||||
public static ClientCertificate getClientCertificate(JapHttpRequest request) {
|
||||
List<ClientSecretAuthMethod> clientSecretAuthMethods = JapIds.getIdsConfig().getClientSecretAuthMethods();
|
||||
if (ObjectUtil.isEmpty(clientSecretAuthMethods)) {
|
||||
clientSecretAuthMethods = Collections.singletonList(ClientSecretAuthMethod.ALL);
|
||||
@ -63,13 +63,13 @@ public class ClientCertificateUtil {
|
||||
return new ClientCertificate();
|
||||
}
|
||||
|
||||
private static ClientCertificate getClientCertificateFromRequestParameter(HttpServletRequest request) {
|
||||
private static ClientCertificate getClientCertificateFromRequestParameter(JapHttpRequest request) {
|
||||
String clientId = RequestUtil.getParam(IdsConsts.CLIENT_ID, request);
|
||||
String clientSecret = RequestUtil.getParam(IdsConsts.CLIENT_SECRET, request);
|
||||
return new ClientCertificate(clientId, clientSecret);
|
||||
}
|
||||
|
||||
private static ClientCertificate getClientCertificateFromHeader(HttpServletRequest request) {
|
||||
private static ClientCertificate getClientCertificateFromHeader(JapHttpRequest request) {
|
||||
String authorizationHeader = RequestUtil.getHeader(IdsConsts.AUTHORIZATION_HEADER_NAME, request);
|
||||
if (StringUtil.isNotEmpty(authorizationHeader)) {
|
||||
BasicCredentials credentials = BasicCredentials.parse(authorizationHeader);
|
||||
|
@ -15,12 +15,12 @@
|
||||
*/
|
||||
package com.fujieid.jap.ids.util;
|
||||
|
||||
import com.fujieid.jap.core.util.RequestUtil;
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.http.RequestUtil;
|
||||
import com.fujieid.jap.ids.JapIds;
|
||||
import com.fujieid.jap.ids.config.IdsConfig;
|
||||
import com.fujieid.jap.ids.exception.IdsException;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
@ -32,7 +32,7 @@ import java.util.Optional;
|
||||
*/
|
||||
public class EndpointUtil {
|
||||
|
||||
public static String getIssuer(HttpServletRequest request) {
|
||||
public static String getIssuer(JapHttpRequest request) {
|
||||
IdsConfig config = JapIds.getIdsConfig();
|
||||
if (config.isEnableDynamicIssuer() && null == request) {
|
||||
throw new IdsException("The second-level domain name verification has been enabled, the HTTP request cannot be empty");
|
||||
@ -46,67 +46,67 @@ public class EndpointUtil {
|
||||
}
|
||||
|
||||
|
||||
public static String getLoginUrl(HttpServletRequest request) {
|
||||
public static String getLoginUrl(JapHttpRequest request) {
|
||||
IdsConfig config = JapIds.getIdsConfig();
|
||||
return getIssuer(request) + config.getLoginUrl();
|
||||
}
|
||||
|
||||
public static String getErrorUrl(HttpServletRequest request) {
|
||||
public static String getErrorUrl(JapHttpRequest request) {
|
||||
IdsConfig config = JapIds.getIdsConfig();
|
||||
return getIssuer(request) + config.getErrorUrl();
|
||||
}
|
||||
|
||||
public static String getAuthorizeUrl(HttpServletRequest request) {
|
||||
public static String getAuthorizeUrl(JapHttpRequest request) {
|
||||
IdsConfig config = JapIds.getIdsConfig();
|
||||
return getIssuer(request) + config.getAuthorizeUrl();
|
||||
}
|
||||
|
||||
public static String getAuthorizeAutoApproveUrl(HttpServletRequest request) {
|
||||
public static String getAuthorizeAutoApproveUrl(JapHttpRequest request) {
|
||||
IdsConfig config = JapIds.getIdsConfig();
|
||||
return getIssuer(request) + config.getAuthorizeAutoApproveUrl();
|
||||
}
|
||||
|
||||
public static String getTokenUrl(HttpServletRequest request) {
|
||||
public static String getTokenUrl(JapHttpRequest request) {
|
||||
IdsConfig config = JapIds.getIdsConfig();
|
||||
return getIssuer(request) + config.getTokenUrl();
|
||||
}
|
||||
|
||||
public static String getUserinfoUrl(HttpServletRequest request) {
|
||||
public static String getUserinfoUrl(JapHttpRequest request) {
|
||||
IdsConfig config = JapIds.getIdsConfig();
|
||||
return getIssuer(request) + config.getUserinfoUrl();
|
||||
}
|
||||
|
||||
public static String getRegistrationUrl(HttpServletRequest request) {
|
||||
public static String getRegistrationUrl(JapHttpRequest request) {
|
||||
IdsConfig config = JapIds.getIdsConfig();
|
||||
return getIssuer(request) + config.getRegistrationUrl();
|
||||
}
|
||||
|
||||
public static String getEndSessionUrl(HttpServletRequest request) {
|
||||
public static String getEndSessionUrl(JapHttpRequest request) {
|
||||
IdsConfig config = JapIds.getIdsConfig();
|
||||
return getIssuer(request) + config.getEndSessionUrl();
|
||||
}
|
||||
|
||||
public static String getCheckSessionUrl(HttpServletRequest request) {
|
||||
public static String getCheckSessionUrl(JapHttpRequest request) {
|
||||
IdsConfig config = JapIds.getIdsConfig();
|
||||
return getIssuer(request) + config.getCheckSessionUrl();
|
||||
}
|
||||
|
||||
public static String getLogoutRedirectUrl(HttpServletRequest request) {
|
||||
public static String getLogoutRedirectUrl(JapHttpRequest request) {
|
||||
IdsConfig config = JapIds.getIdsConfig();
|
||||
return getIssuer(request) + config.getLogoutRedirectUrl();
|
||||
}
|
||||
|
||||
public static String getJwksUrl(HttpServletRequest request) {
|
||||
public static String getJwksUrl(JapHttpRequest request) {
|
||||
IdsConfig config = JapIds.getIdsConfig();
|
||||
return getIssuer(request) + config.getJwksUrl();
|
||||
}
|
||||
|
||||
public static String getDiscoveryUrl(HttpServletRequest request) {
|
||||
public static String getDiscoveryUrl(JapHttpRequest request) {
|
||||
IdsConfig config = JapIds.getIdsConfig();
|
||||
return getIssuer(request) + config.getDiscoveryUrl();
|
||||
}
|
||||
|
||||
public static String getLoginPageUrl(HttpServletRequest request) {
|
||||
public static String getLoginPageUrl(JapHttpRequest request) {
|
||||
IdsConfig config = JapIds.getIdsConfig();
|
||||
if (config.isExternalLoginPageUrl()) {
|
||||
return config.getLoginPageUrl();
|
||||
@ -114,7 +114,7 @@ public class EndpointUtil {
|
||||
return getIssuer(request) + config.getLoginPageUrl();
|
||||
}
|
||||
|
||||
public static String getConfirmPageUrl(HttpServletRequest request) {
|
||||
public static String getConfirmPageUrl(JapHttpRequest request) {
|
||||
IdsConfig config = JapIds.getIdsConfig();
|
||||
if (config.isExternalConfirmPageUrl()) {
|
||||
return config.getConfirmPageUrl();
|
||||
|
@ -78,7 +78,13 @@ public class OauthUtil {
|
||||
public static Set<String> validateScope(String requestScopes, String clientScopes) {
|
||||
|
||||
if (StringUtil.isEmpty(requestScopes)) {
|
||||
throw new InvalidScopeException(ErrorResponse.INVALID_SCOPE);
|
||||
// OPTIONAL. The scope of the access request.
|
||||
// https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.1
|
||||
// https://datatracker.ietf.org/doc/html/rfc6749#section-4.2.1
|
||||
// https://datatracker.ietf.org/doc/html/rfc6749#section-4.3.2
|
||||
// https://datatracker.ietf.org/doc/html/rfc6749#section-4.4.2
|
||||
// https://datatracker.ietf.org/doc/html/rfc6749#section-6
|
||||
return new HashSet<>();
|
||||
}
|
||||
Set<String> scopes = OauthUtil.convertStrToList(requestScopes);
|
||||
|
||||
|
@ -16,7 +16,8 @@
|
||||
package com.fujieid.jap.ids.util;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.fujieid.jap.core.util.RequestUtil;
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.http.RequestUtil;
|
||||
import com.fujieid.jap.ids.JapIds;
|
||||
import com.fujieid.jap.ids.exception.IdsTokenException;
|
||||
import com.fujieid.jap.ids.exception.InvalidTokenException;
|
||||
@ -26,7 +27,6 @@ import com.fujieid.jap.ids.model.enums.TokenAuthMethod;
|
||||
import com.fujieid.jap.ids.service.IdsTokenService;
|
||||
import com.xkcoding.json.util.StringUtil;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@ -44,7 +44,7 @@ public class TokenUtil {
|
||||
* @param request request
|
||||
* @return String
|
||||
*/
|
||||
public static String getAccessToken(HttpServletRequest request) {
|
||||
public static String getAccessToken(JapHttpRequest request) {
|
||||
List<TokenAuthMethod> tokenAuthMethods = JapIds.getIdsConfig().getTokenAuthMethods();
|
||||
if (ObjectUtil.isEmpty(tokenAuthMethods)) {
|
||||
tokenAuthMethods = Collections.singletonList(TokenAuthMethod.ALL);
|
||||
@ -79,7 +79,7 @@ public class TokenUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String getAccessTokenFromUrl(HttpServletRequest request) {
|
||||
private static String getAccessTokenFromUrl(JapHttpRequest request) {
|
||||
String accessToken = RequestUtil.getParam(IdsConsts.ACCESS_TOKEN, request);
|
||||
if (StringUtil.isNotEmpty(accessToken)) {
|
||||
return accessToken;
|
||||
@ -87,12 +87,12 @@ public class TokenUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String getAccessTokenFromHeader(HttpServletRequest request) {
|
||||
private static String getAccessTokenFromHeader(JapHttpRequest request) {
|
||||
String accessToken = RequestUtil.getHeader(IdsConsts.AUTHORIZATION_HEADER_NAME, request);
|
||||
return BearerToken.parse(accessToken);
|
||||
}
|
||||
|
||||
private static String getAccessTokenFromCookie(HttpServletRequest request) {
|
||||
private static String getAccessTokenFromCookie(JapHttpRequest request) {
|
||||
return RequestUtil.getCookieVal(request, IdsConsts.ACCESS_TOKEN);
|
||||
}
|
||||
|
||||
@ -170,7 +170,7 @@ public class TokenUtil {
|
||||
}
|
||||
|
||||
|
||||
public static void invalidateToken(HttpServletRequest request) {
|
||||
public static void invalidateToken(JapHttpRequest request) {
|
||||
String accessTokenStr = TokenUtil.getAccessToken(request);
|
||||
AccessToken accessToken = TokenUtil.getByAccessToken(accessTokenStr);
|
||||
if (null != accessToken) {
|
||||
|
@ -1,15 +1,15 @@
|
||||
package com.fujieid.jap.ids;
|
||||
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.http.jakarta.JakartaRequestAdapter;
|
||||
import com.fujieid.jap.ids.config.IdsConfig;
|
||||
import com.fujieid.jap.ids.config.JwtConfig;
|
||||
import com.fujieid.jap.ids.context.IdsContext;
|
||||
import com.xkcoding.json.JsonUtil;
|
||||
import org.junit.Before;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
@ -23,11 +23,10 @@ import static org.mockito.Mockito.when;
|
||||
public class BaseIdsTest {
|
||||
|
||||
|
||||
public JapHttpRequest request;
|
||||
@Mock
|
||||
protected HttpServletRequest httpServletRequestMock;
|
||||
@Mock
|
||||
protected HttpServletResponse httpServletResponseMock;
|
||||
@Mock
|
||||
protected HttpSession httpsSessionMock;
|
||||
protected String issuer = "http://www.baidu.com";
|
||||
|
||||
@ -36,6 +35,7 @@ public class BaseIdsTest {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
// Arrange
|
||||
when(httpServletRequestMock.getSession()).thenReturn(httpsSessionMock);
|
||||
this.request = new JakartaRequestAdapter(httpServletRequestMock);
|
||||
|
||||
// 注册 JAP IDS 上下文
|
||||
JapIds.registerContext(new IdsContext()
|
||||
|
@ -1,21 +0,0 @@
|
||||
package com.fujieid.jap.ids.endpoint;
|
||||
|
||||
import com.fujieid.jap.ids.BaseIdsTest;
|
||||
import com.fujieid.jap.ids.exception.InvalidRequestException;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class ApprovalEndpointTest extends BaseIdsTest {
|
||||
|
||||
@Test
|
||||
public void showConfirmPage() throws IOException {
|
||||
Assert.assertThrows(InvalidRequestException.class, () -> new ApprovalEndpoint().showConfirmPage(httpServletRequestMock, httpServletResponseMock));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAuthClientInfo() {
|
||||
Assert.assertThrows(InvalidRequestException.class, () -> new ApprovalEndpoint().getAuthClientInfo(httpServletRequestMock));
|
||||
}
|
||||
}
|
@ -15,8 +15,8 @@
|
||||
*/
|
||||
package com.fujieid.jap.ids.pipeline;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.http.JapHttpResponse;
|
||||
|
||||
/**
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
@ -27,24 +27,24 @@ public class CustomizeFilterPipeline implements IdsFilterPipeline {
|
||||
/**
|
||||
* Callback when the program is abnormal
|
||||
*
|
||||
* @param servletRequest current HTTP request
|
||||
* @param servletResponse current HTTP response
|
||||
* @param throwable any exception thrown on handler execution, if any.
|
||||
* @param request current HTTP request
|
||||
* @param response current HTTP response
|
||||
* @param throwable any exception thrown on handler execution, if any.
|
||||
*/
|
||||
@Override
|
||||
public void errorHandle(ServletRequest servletRequest, ServletResponse servletResponse, Throwable throwable) {
|
||||
public void errorHandle(JapHttpRequest request, JapHttpResponse response, Throwable throwable) {
|
||||
System.out.println("CustomizeFilterPipeline >> errorHandle");
|
||||
}
|
||||
|
||||
/**
|
||||
* Operations before business process processing, such as initializing resources, etc.
|
||||
*
|
||||
* @param servletRequest current HTTP request
|
||||
* @param servletResponse current HTTP response
|
||||
* @param request current HTTP request
|
||||
* @param response current HTTP response
|
||||
* @return boolean
|
||||
*/
|
||||
@Override
|
||||
public boolean preHandle(ServletRequest servletRequest, ServletResponse servletResponse) {
|
||||
public boolean preHandle(JapHttpRequest request, JapHttpResponse response) {
|
||||
System.out.println("CustomizeFilterPipeline >> preHandle");
|
||||
return true;
|
||||
}
|
||||
@ -52,12 +52,12 @@ public class CustomizeFilterPipeline implements IdsFilterPipeline {
|
||||
/**
|
||||
* Intercept the execution of a handler
|
||||
*
|
||||
* @param servletRequest current HTTP request
|
||||
* @param servletResponse current HTTP response
|
||||
* @param request current HTTP request
|
||||
* @param response current HTTP response
|
||||
* @return Object
|
||||
*/
|
||||
@Override
|
||||
public Object postHandle(ServletRequest servletRequest, ServletResponse servletResponse) {
|
||||
public Object postHandle(JapHttpRequest request, JapHttpResponse response) {
|
||||
System.out.println("CustomizeFilterPipeline >> postHandle");
|
||||
return null;
|
||||
}
|
||||
@ -65,11 +65,11 @@ public class CustomizeFilterPipeline implements IdsFilterPipeline {
|
||||
/**
|
||||
* Callback after business process processing is completed, such as recycling resources, recording status, etc.
|
||||
*
|
||||
* @param servletRequest current HTTP request
|
||||
* @param servletResponse current HTTP response
|
||||
* @param request current HTTP request
|
||||
* @param response current HTTP response
|
||||
*/
|
||||
@Override
|
||||
public void afterHandle(ServletRequest servletRequest, ServletResponse servletResponse) {
|
||||
public void afterHandle(JapHttpRequest request, JapHttpResponse response) {
|
||||
System.out.println("CustomizeFilterPipeline >> afterHandle");
|
||||
}
|
||||
}
|
||||
|
@ -15,11 +15,10 @@
|
||||
*/
|
||||
package com.fujieid.jap.ids.pipeline;
|
||||
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.http.JapHttpResponse;
|
||||
import com.fujieid.jap.ids.model.UserInfo;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
/**
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0.0
|
||||
@ -29,24 +28,24 @@ public class CustomizeSignInPipeline implements IdsSignInPipeline {
|
||||
/**
|
||||
* Callback when the program is abnormal
|
||||
*
|
||||
* @param servletRequest current HTTP request
|
||||
* @param servletResponse current HTTP response
|
||||
* @param throwable any exception thrown on handler execution, if any.
|
||||
* @param request current HTTP request
|
||||
* @param response current HTTP response
|
||||
* @param throwable any exception thrown on handler execution, if any.
|
||||
*/
|
||||
@Override
|
||||
public void errorHandle(ServletRequest servletRequest, ServletResponse servletResponse, Throwable throwable) {
|
||||
public void errorHandle(JapHttpRequest request, JapHttpResponse response, Throwable throwable) {
|
||||
System.out.println("CustomizeSignInPipeline >> errorHandle");
|
||||
}
|
||||
|
||||
/**
|
||||
* Operations before business process processing, such as initializing resources, etc.
|
||||
*
|
||||
* @param servletRequest current HTTP request
|
||||
* @param servletResponse current HTTP response
|
||||
* @param request current HTTP request
|
||||
* @param response current HTTP response
|
||||
* @return boolean
|
||||
*/
|
||||
@Override
|
||||
public boolean preHandle(ServletRequest servletRequest, ServletResponse servletResponse) {
|
||||
public boolean preHandle(JapHttpRequest request, JapHttpResponse response) {
|
||||
System.out.println("CustomizeSignInPipeline >> preHandle");
|
||||
return true;
|
||||
}
|
||||
@ -54,12 +53,12 @@ public class CustomizeSignInPipeline implements IdsSignInPipeline {
|
||||
/**
|
||||
* Intercept the execution of a handler
|
||||
*
|
||||
* @param servletRequest current HTTP request
|
||||
* @param servletResponse current HTTP response
|
||||
* @param request current HTTP request
|
||||
* @param response current HTTP response
|
||||
* @return UserInfo
|
||||
*/
|
||||
@Override
|
||||
public UserInfo postHandle(ServletRequest servletRequest, ServletResponse servletResponse) {
|
||||
public UserInfo postHandle(JapHttpRequest request, JapHttpResponse response) {
|
||||
System.out.println("CustomizeSignInPipeline >> postHandle");
|
||||
return null;
|
||||
}
|
||||
@ -67,11 +66,11 @@ public class CustomizeSignInPipeline implements IdsSignInPipeline {
|
||||
/**
|
||||
* Callback after business process processing is completed, such as recycling resources, recording status, etc.
|
||||
*
|
||||
* @param servletRequest current HTTP request
|
||||
* @param servletResponse current HTTP response
|
||||
* @param request current HTTP request
|
||||
* @param response current HTTP response
|
||||
*/
|
||||
@Override
|
||||
public void afterHandle(ServletRequest servletRequest, ServletResponse servletResponse) {
|
||||
public void afterHandle(JapHttpRequest request, JapHttpResponse response) {
|
||||
System.out.println("CustomizeSignInPipeline >> afterHandle");
|
||||
}
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ public class IdsTokenProviderTest extends BaseIdsTest {
|
||||
@Test
|
||||
public void generateAuthorizationCodeResponse() {
|
||||
this.initParam();
|
||||
Assert.assertThrows(InvalidCodeException.class, () -> idsTokenProvider.generateAuthorizationCodeResponse(idsRequestParam, httpServletRequestMock));
|
||||
Assert.assertThrows(InvalidCodeException.class, () -> idsTokenProvider.generateAuthorizationCodeResponse(idsRequestParam, request));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -47,7 +47,7 @@ public class IdsTokenProviderTest extends BaseIdsTest {
|
||||
this.initParam();
|
||||
String code = oauth2Service.createAuthorizationCode(idsRequestParam, new UserInfo(), 100000L);
|
||||
idsRequestParam.setCode(code);
|
||||
IdsResponse<String, Object> response = idsTokenProvider.generateAuthorizationCodeResponse(idsRequestParam, httpServletRequestMock);
|
||||
IdsResponse<String, Object> response = idsTokenProvider.generateAuthorizationCodeResponse(idsRequestParam, request);
|
||||
System.out.println(response);
|
||||
Assert.assertNotNull(response);
|
||||
}
|
||||
@ -58,7 +58,7 @@ public class IdsTokenProviderTest extends BaseIdsTest {
|
||||
String code = oauth2Service.createAuthorizationCode(idsRequestParam, new UserInfo(), 100000L);
|
||||
idsRequestParam.setCode(code);
|
||||
idsRequestParam.setClientId("asdasd");
|
||||
Assert.assertThrows(InvalidClientException.class, () -> idsTokenProvider.generateAuthorizationCodeResponse(idsRequestParam, httpServletRequestMock));
|
||||
Assert.assertThrows(InvalidClientException.class, () -> idsTokenProvider.generateAuthorizationCodeResponse(idsRequestParam, request));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -67,7 +67,7 @@ public class IdsTokenProviderTest extends BaseIdsTest {
|
||||
String code = oauth2Service.createAuthorizationCode(idsRequestParam, new UserInfo(), 100000L);
|
||||
idsRequestParam.setCode(code);
|
||||
idsRequestParam.setGrantType("asdasd");
|
||||
Assert.assertThrows(UnsupportedGrantTypeException.class, () -> idsTokenProvider.generateAuthorizationCodeResponse(idsRequestParam, httpServletRequestMock));
|
||||
Assert.assertThrows(UnsupportedGrantTypeException.class, () -> idsTokenProvider.generateAuthorizationCodeResponse(idsRequestParam, request));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -76,7 +76,7 @@ public class IdsTokenProviderTest extends BaseIdsTest {
|
||||
String code = oauth2Service.createAuthorizationCode(idsRequestParam, new UserInfo(), 100000L);
|
||||
idsRequestParam.setCode(code);
|
||||
idsRequestParam.setRedirectUri("asdasd");
|
||||
Assert.assertThrows(InvalidRedirectUriException.class, () -> idsTokenProvider.generateAuthorizationCodeResponse(idsRequestParam, httpServletRequestMock));
|
||||
Assert.assertThrows(InvalidRedirectUriException.class, () -> idsTokenProvider.generateAuthorizationCodeResponse(idsRequestParam, request));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -85,7 +85,7 @@ public class IdsTokenProviderTest extends BaseIdsTest {
|
||||
String code = oauth2Service.createAuthorizationCode(idsRequestParam, new UserInfo(), 100000L);
|
||||
idsRequestParam.setCode(code);
|
||||
idsRequestParam.setClientSecret("asdasd");
|
||||
Assert.assertThrows(InvalidClientException.class, () -> idsTokenProvider.generateAuthorizationCodeResponse(idsRequestParam, httpServletRequestMock));
|
||||
Assert.assertThrows(InvalidClientException.class, () -> idsTokenProvider.generateAuthorizationCodeResponse(idsRequestParam, request));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -19,6 +19,7 @@ import com.fujieid.jap.core.spi.JapServiceLoader;
|
||||
import com.fujieid.jap.ids.pipeline.IdsFilterPipeline;
|
||||
import com.fujieid.jap.ids.pipeline.IdsPipeline;
|
||||
import com.fujieid.jap.ids.pipeline.IdsSignInPipeline;
|
||||
import com.fujieid.jap.ids.service.IdsUserService;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
@ -30,6 +31,16 @@ import java.util.List;
|
||||
*/
|
||||
public class ServiceLoaderTest {
|
||||
|
||||
@Test
|
||||
public void idsUserService() {
|
||||
// initialize
|
||||
List<IdsUserService> list = JapServiceLoader.load(IdsUserService.class);
|
||||
list.forEach(idsPipeline -> {
|
||||
System.out.println(idsPipeline);
|
||||
System.out.println(idsPipeline.getClass());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadIdsPipeline() {
|
||||
List<IdsPipeline> list = JapServiceLoader.load(IdsPipeline.class);
|
||||
|
@ -32,6 +32,16 @@
|
||||
<dependency>
|
||||
<groupId>com.warrenstrange</groupId>
|
||||
<artifactId>googleauth</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
@ -19,10 +19,10 @@ import cn.hutool.core.img.ImgUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.log.Log;
|
||||
import cn.hutool.log.LogFactory;
|
||||
import com.fujieid.jap.http.JapHttpResponse;
|
||||
import com.fujieid.jap.sso.util.QrCodeUtil;
|
||||
import com.warrenstrange.googleauth.*;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@ -122,7 +122,7 @@ public class JapMfa {
|
||||
* @param issuer The issuer name. This parameter cannot contain the colon (:) character.
|
||||
* @param response HttpServletResponse
|
||||
*/
|
||||
public void createOtpQrcode(String username, String issuer, HttpServletResponse response) {
|
||||
public void createOtpQrcode(String username, String issuer, JapHttpResponse response) {
|
||||
try {
|
||||
QrCodeUtil.generate(getTotpUrl(username, issuer),
|
||||
mfaConfig.getQrcodeWidth(), mfaConfig.getQrcodeHeight(),
|
||||
|
@ -36,7 +36,7 @@ public class JapMfaConfig {
|
||||
*/
|
||||
private long period = 30000;
|
||||
/**
|
||||
* the crypto algorithm (HmacSHA1, HmacSHA256, HmacSHA512)
|
||||
* the crypto algorithm (HMACSHA1, HMACSHA256, HMACSHA512)
|
||||
*/
|
||||
private JapMfaAlgorithm algorithm = JapMfaAlgorithm.HmacSHA1;
|
||||
|
||||
|
@ -262,7 +262,7 @@ public class QrCodeUtil {
|
||||
*/
|
||||
public HashMap<EncodeHintType, Object> toHints() {
|
||||
// 配置
|
||||
final HashMap<EncodeHintType, Object> hints = new HashMap<>();
|
||||
final HashMap<EncodeHintType, Object> hints = new HashMap<>(7);
|
||||
if (null != this.charset) {
|
||||
hints.put(EncodeHintType.CHARACTER_SET, charset.toString().toLowerCase());
|
||||
}
|
||||
|
@ -46,8 +46,8 @@ public class JapMfaTest {
|
||||
private static void varifyCode(JapMfa japMfa) {
|
||||
String secretKey = japMfa.getSecretKey(username);
|
||||
|
||||
System.out.println("1. 你需要打开生成的文件(或者将 Base64 字符串直接粘贴到浏览器地址会回车)");
|
||||
System.out.println("2. 然后使用 OTP 工具扫描二维码");
|
||||
System.out.println("1. 点击上方打印的URL链接");
|
||||
System.out.println("2. 然后使用 OTP 工具扫描二维码(如果无法识别,请保存到本地后打开本地文件重新进行识别)");
|
||||
System.out.println("3. 在控制台输入 code");
|
||||
Scanner scanner = new Scanner(System.in);
|
||||
Integer consoleInput = null;
|
||||
|
@ -77,12 +77,12 @@ public class OAuthConfig extends AuthenticateConfig {
|
||||
* "token" for requesting an access token (implicit grant) as described by Section 4.2.1 (<a href="https://tools.ietf.org/html/rfc6749#section-4.2.1" target="_blank">https://tools.ietf.org/html/rfc6749#section-4.2.1</a>),
|
||||
* or a registered extension value as described by Section 8.4 (<a href="https://tools.ietf.org/html/rfc6749#section-8.4" target="_blank">https://tools.ietf.org/html/rfc6749#section-8.4</a>).
|
||||
*/
|
||||
private Oauth2ResponseType responseType = Oauth2ResponseType.none;
|
||||
private Oauth2ResponseType responseType = Oauth2ResponseType.NONE;
|
||||
|
||||
/**
|
||||
* The optional value is: {@code authorization_code}, {@code password}, {@code client_credentials}
|
||||
* The optional value is: {@code AUTHORIZATION_CODE}, {@code PASSWORD}, {@code CLIENT_CREDENTIALS}
|
||||
*/
|
||||
private Oauth2GrantType grantType = Oauth2GrantType.authorization_code;
|
||||
private Oauth2GrantType grantType = Oauth2GrantType.AUTHORIZATION_CODE;
|
||||
|
||||
/**
|
||||
* The scope supported by the OAuth platform
|
||||
@ -98,7 +98,7 @@ public class OAuthConfig extends AuthenticateConfig {
|
||||
private String state;
|
||||
|
||||
/**
|
||||
* The scope supported by the OAuth platform
|
||||
* Whether to enable PKCE mode
|
||||
*/
|
||||
private boolean enablePkce;
|
||||
|
||||
@ -110,6 +110,11 @@ public class OAuthConfig extends AuthenticateConfig {
|
||||
*/
|
||||
private PkceCodeChallengeMethod codeChallengeMethod = PkceCodeChallengeMethod.S256;
|
||||
|
||||
/**
|
||||
* In pkce mode, the expiration time of codeverifier, in milliseconds, default is 3 minutes
|
||||
*/
|
||||
private long codeVerifierTimeout = 180000;
|
||||
|
||||
/**
|
||||
* The username in `Resource Owner Password Credentials Grant`
|
||||
*
|
||||
@ -124,11 +129,6 @@ public class OAuthConfig extends AuthenticateConfig {
|
||||
*/
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* In pkce mode, the expiration time of codeverifier, in milliseconds, default is 3 minutes
|
||||
*/
|
||||
private long codeVerifierTimeout = 180000;
|
||||
|
||||
/**
|
||||
* When {@code verifyState} is true, it will check whether the state in authorization request is consistent with that in callback request
|
||||
*/
|
||||
|
@ -25,17 +25,17 @@ public enum Oauth2GrantType {
|
||||
/**
|
||||
* Authorization Code Grant
|
||||
*/
|
||||
authorization_code,
|
||||
AUTHORIZATION_CODE,
|
||||
/**
|
||||
* Resource Owner Password Credentials Grant
|
||||
*/
|
||||
password,
|
||||
PASSWORD,
|
||||
/**
|
||||
* Client Credentials Grant
|
||||
*/
|
||||
client_credentials,
|
||||
CLIENT_CREDENTIALS,
|
||||
/**
|
||||
* Refreshing an Access Token
|
||||
*/
|
||||
refresh_token
|
||||
REFRESH_TOKEN
|
||||
}
|
||||
|
@ -25,13 +25,13 @@ public enum Oauth2ResponseType {
|
||||
/**
|
||||
* When authorization code mode or implicit authorization mode is not used, ResponseType needs to be set to {@code none}
|
||||
*/
|
||||
none,
|
||||
NONE,
|
||||
/**
|
||||
* Authorization Code Grant
|
||||
*/
|
||||
code,
|
||||
CODE,
|
||||
/**
|
||||
* Implicit Grant
|
||||
*/
|
||||
token
|
||||
TOKEN
|
||||
}
|
||||
|
@ -27,14 +27,14 @@ import com.fujieid.jap.core.exception.JapOauth2Exception;
|
||||
import com.fujieid.jap.core.result.JapErrorCode;
|
||||
import com.fujieid.jap.core.result.JapResponse;
|
||||
import com.fujieid.jap.core.strategy.AbstractJapStrategy;
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.http.JapHttpResponse;
|
||||
import com.fujieid.jap.oauth2.pkce.PkceHelper;
|
||||
import com.fujieid.jap.oauth2.token.AccessToken;
|
||||
import com.fujieid.jap.oauth2.token.AccessTokenHelper;
|
||||
import com.xkcoding.json.util.Kv;
|
||||
import com.xkcoding.json.util.StringUtil;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@ -82,7 +82,7 @@ public class Oauth2Strategy extends AbstractJapStrategy {
|
||||
* @param response The response to authenticate
|
||||
*/
|
||||
@Override
|
||||
public JapResponse authenticate(AuthenticateConfig config, HttpServletRequest request, HttpServletResponse response) {
|
||||
public JapResponse authenticate(AuthenticateConfig config, JapHttpRequest request, JapHttpResponse response) {
|
||||
|
||||
try {
|
||||
Oauth2Util.checkOauthCallbackRequest(request.getParameter("error"), request.getParameter("error_description"),
|
||||
@ -109,8 +109,8 @@ public class Oauth2Strategy extends AbstractJapStrategy {
|
||||
return JapResponse.error(e.getErrorCode(), e.getErrorMessage());
|
||||
}
|
||||
|
||||
boolean isPasswordOrClientMode = authConfig.getGrantType() == Oauth2GrantType.password
|
||||
|| authConfig.getGrantType() == Oauth2GrantType.client_credentials;
|
||||
boolean isPasswordOrClientMode = authConfig.getGrantType() == Oauth2GrantType.PASSWORD
|
||||
|| authConfig.getGrantType() == Oauth2GrantType.CLIENT_CREDENTIALS;
|
||||
|
||||
// If it is not a callback request, it must be a request to jump to the authorization link
|
||||
// If it is a password authorization request or a client authorization request, the token will be obtained directly
|
||||
@ -152,7 +152,7 @@ public class Oauth2Strategy extends AbstractJapStrategy {
|
||||
return JapResponse.error(e.getErrorCode(), e.getErrorMessage());
|
||||
}
|
||||
OAuthConfig authConfig = (OAuthConfig) config;
|
||||
if (authConfig.getGrantType() != Oauth2GrantType.refresh_token) {
|
||||
if (authConfig.getGrantType() != Oauth2GrantType.REFRESH_TOKEN) {
|
||||
return JapResponse.error(JapErrorCode.INVALID_GRANT_TYPE);
|
||||
}
|
||||
AccessToken accessToken = null;
|
||||
@ -233,8 +233,8 @@ public class Oauth2Strategy extends AbstractJapStrategy {
|
||||
String url = null;
|
||||
// 4.1. Authorization Code Grant https://tools.ietf.org/html/rfc6749#section-4.1
|
||||
// 4.2. Implicit Grant https://tools.ietf.org/html/rfc6749#section-4.2
|
||||
if (authConfig.getResponseType() == Oauth2ResponseType.code ||
|
||||
authConfig.getResponseType() == Oauth2ResponseType.token) {
|
||||
if (authConfig.getResponseType() == Oauth2ResponseType.CODE ||
|
||||
authConfig.getResponseType() == Oauth2ResponseType.TOKEN) {
|
||||
url = generateAuthorizationCodeGrantUrl(authConfig);
|
||||
}
|
||||
return url;
|
||||
@ -267,7 +267,7 @@ public class Oauth2Strategy extends AbstractJapStrategy {
|
||||
params.put("state", authConfig.getState());
|
||||
JapAuthentication.getContext().getCache().set(Oauth2Const.STATE_CACHE_KEY.concat(authConfig.getClientId()), state);
|
||||
// Pkce is only applicable to authorization code mode
|
||||
if (Oauth2ResponseType.code == authConfig.getResponseType() && authConfig.isEnablePkce()) {
|
||||
if (Oauth2ResponseType.CODE == authConfig.getResponseType() && authConfig.isEnablePkce()) {
|
||||
params.putAll(PkceHelper.generatePkceParameters(authConfig));
|
||||
}
|
||||
String query = URLUtil.buildQuery(params, StandardCharsets.UTF_8);
|
||||
|
@ -22,12 +22,14 @@ import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import com.fujieid.jap.core.context.JapAuthentication;
|
||||
import com.fujieid.jap.core.exception.JapOauth2Exception;
|
||||
import com.fujieid.jap.core.exception.OidcException;
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.oauth2.pkce.PkceCodeChallengeMethod;
|
||||
import com.xkcoding.http.HttpUtil;
|
||||
import com.xkcoding.http.support.SimpleHttpResponse;
|
||||
import com.xkcoding.json.JsonUtil;
|
||||
import com.xkcoding.json.util.Kv;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
@ -82,7 +84,7 @@ public class Oauth2Util {
|
||||
}
|
||||
if (responseKv.containsKey("error") && ObjectUtil.isNotEmpty(responseKv.get("error"))) {
|
||||
throw new JapOauth2Exception(Optional.ofNullable(errorMsg).orElse("") +
|
||||
responseKv.get("error_description") + " " + responseKv.toString());
|
||||
responseKv.get("error_description") + " " + responseKv);
|
||||
}
|
||||
}
|
||||
|
||||
@ -131,11 +133,11 @@ public class Oauth2Util {
|
||||
// For authorization code mode and implicit authorization mode
|
||||
// refer to: https://tools.ietf.org/html/rfc6749#section-4.1
|
||||
// refer to: https://tools.ietf.org/html/rfc6749#section-4.2
|
||||
if (oAuthConfig.getResponseType() == Oauth2ResponseType.code ||
|
||||
oAuthConfig.getResponseType() == Oauth2ResponseType.token) {
|
||||
if (oAuthConfig.getResponseType() == Oauth2ResponseType.CODE ||
|
||||
oAuthConfig.getResponseType() == Oauth2ResponseType.TOKEN) {
|
||||
|
||||
if (oAuthConfig.getResponseType() == Oauth2ResponseType.code) {
|
||||
if (oAuthConfig.getGrantType() != Oauth2GrantType.authorization_code) {
|
||||
if (oAuthConfig.getResponseType() == Oauth2ResponseType.CODE) {
|
||||
if (oAuthConfig.getGrantType() != Oauth2GrantType.AUTHORIZATION_CODE) {
|
||||
throw new JapOauth2Exception("Invalid grantType `" + oAuthConfig.getGrantType() + "`. " +
|
||||
"When using authorization code mode, grantType must be `authorization_code`");
|
||||
}
|
||||
@ -164,11 +166,11 @@ public class Oauth2Util {
|
||||
// For password mode
|
||||
// refer to: https://tools.ietf.org/html/rfc6749#section-4.3
|
||||
else {
|
||||
if (oAuthConfig.getGrantType() != Oauth2GrantType.password && oAuthConfig.getGrantType() != Oauth2GrantType.client_credentials) {
|
||||
if (oAuthConfig.getGrantType() != Oauth2GrantType.PASSWORD && oAuthConfig.getGrantType() != Oauth2GrantType.CLIENT_CREDENTIALS) {
|
||||
throw new JapOauth2Exception("When the response type is none in the oauth2 strategy, a grant type other " +
|
||||
"than the authorization code must be used: " + oAuthConfig.getGrantType());
|
||||
}
|
||||
if (oAuthConfig.getGrantType() == Oauth2GrantType.password) {
|
||||
if (oAuthConfig.getGrantType() == Oauth2GrantType.PASSWORD) {
|
||||
if (!StrUtil.isAllNotEmpty(oAuthConfig.getUsername(), oAuthConfig.getPassword())) {
|
||||
throw new JapOauth2Exception("Oauth2Strategy requires username and password in password certificate grant");
|
||||
}
|
||||
@ -186,11 +188,11 @@ public class Oauth2Util {
|
||||
* @param oAuthConfig OAuthConfig
|
||||
* @return When true is returned, the current HTTP request is a callback request
|
||||
*/
|
||||
public static boolean isCallback(HttpServletRequest request, OAuthConfig oAuthConfig) {
|
||||
if (oAuthConfig.getResponseType() == Oauth2ResponseType.code) {
|
||||
public static boolean isCallback(JapHttpRequest request, OAuthConfig oAuthConfig) {
|
||||
if (oAuthConfig.getResponseType() == Oauth2ResponseType.CODE) {
|
||||
String code = request.getParameter("code");
|
||||
return !StrUtil.isEmpty(code);
|
||||
} else if (oAuthConfig.getResponseType() == Oauth2ResponseType.token) {
|
||||
} else if (oAuthConfig.getResponseType() == Oauth2ResponseType.TOKEN) {
|
||||
String accessToken = request.getParameter("access_token");
|
||||
return !StrUtil.isEmpty(accessToken);
|
||||
}
|
||||
@ -212,12 +214,20 @@ public class Oauth2Util {
|
||||
*/
|
||||
public static Kv request(Oauth2EndpointMethodType endpointMethodType, String url, Map<String, String> params) {
|
||||
|
||||
String res = null;
|
||||
SimpleHttpResponse res = null;
|
||||
if (null == endpointMethodType || Oauth2EndpointMethodType.GET == endpointMethodType) {
|
||||
res = HttpUtil.get(url, params, false);
|
||||
} else {
|
||||
res = HttpUtil.post(url, params, false);
|
||||
}
|
||||
return JsonUtil.parseKv(res);
|
||||
|
||||
if (!res.isSuccess()) {
|
||||
throw new JapOauth2Exception("Cannot access url: " + url
|
||||
+ " , method: " + endpointMethodType
|
||||
+ " , params: " + params
|
||||
+ " , error details: " + res.getError()
|
||||
);
|
||||
}
|
||||
return JsonUtil.parseKv(res.getBody());
|
||||
}
|
||||
}
|
||||
|
@ -19,17 +19,17 @@ import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.fujieid.jap.core.exception.JapOauth2Exception;
|
||||
import com.fujieid.jap.core.util.JapUtil;
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.oauth2.*;
|
||||
import com.fujieid.jap.oauth2.pkce.PkceHelper;
|
||||
import com.fujieid.jap.oauth2.pkce.PkceParams;
|
||||
import com.xkcoding.json.util.Kv;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Access token helper. Provides a unified access token method {@link AccessTokenHelper#getToken(HttpServletRequest, OAuthConfig, Object[])}
|
||||
* Access token helper. Provides a unified access token method {@link AccessTokenHelper#getToken(JapHttpRequest, OAuthConfig, Object[])}
|
||||
* for different authorization methods
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
@ -49,23 +49,23 @@ public class AccessTokenHelper {
|
||||
* @param obj Optional parameters
|
||||
* @return AccessToken
|
||||
*/
|
||||
public static AccessToken getToken(HttpServletRequest request, OAuthConfig oAuthConfig, Object... obj) throws JapOauth2Exception {
|
||||
public static AccessToken getToken(JapHttpRequest request, OAuthConfig oAuthConfig, Object... obj) throws JapOauth2Exception {
|
||||
if (null == oAuthConfig) {
|
||||
throw new JapOauth2Exception("Oauth2Strategy failed to get AccessToken. OAuthConfig cannot be empty.");
|
||||
}
|
||||
if (oAuthConfig.getResponseType() == Oauth2ResponseType.code) {
|
||||
if (oAuthConfig.getResponseType() == Oauth2ResponseType.CODE) {
|
||||
return getAccessTokenOfAuthorizationCodeMode(request, oAuthConfig);
|
||||
}
|
||||
if (oAuthConfig.getResponseType() == Oauth2ResponseType.token) {
|
||||
if (oAuthConfig.getResponseType() == Oauth2ResponseType.TOKEN) {
|
||||
return getAccessTokenOfImplicitMode(request);
|
||||
}
|
||||
if (oAuthConfig.getGrantType() == Oauth2GrantType.password) {
|
||||
if (oAuthConfig.getGrantType() == Oauth2GrantType.PASSWORD) {
|
||||
return getAccessTokenOfPasswordMode(oAuthConfig);
|
||||
}
|
||||
if (oAuthConfig.getGrantType() == Oauth2GrantType.client_credentials) {
|
||||
if (oAuthConfig.getGrantType() == Oauth2GrantType.CLIENT_CREDENTIALS) {
|
||||
return getAccessTokenOfClientMode(request, oAuthConfig);
|
||||
}
|
||||
if (oAuthConfig.getGrantType() == Oauth2GrantType.refresh_token) {
|
||||
if (oAuthConfig.getGrantType() == Oauth2GrantType.REFRESH_TOKEN) {
|
||||
String refreshToken = null;
|
||||
if (null == obj || obj.length == 0 || null == obj[0] || (refreshToken = String.valueOf(obj[0])).isEmpty()) {
|
||||
throw new JapOauth2Exception("Failed to refresh token, refresh_token is empty.");
|
||||
@ -84,13 +84,13 @@ public class AccessTokenHelper {
|
||||
* @return token request url
|
||||
* @see <a href="https://tools.ietf.org/html/rfc6749#section-4.1" target="_blank">4.1. Authorization Code Grant</a>
|
||||
*/
|
||||
private static AccessToken getAccessTokenOfAuthorizationCodeMode(HttpServletRequest request, OAuthConfig oAuthConfig) throws JapOauth2Exception {
|
||||
private static AccessToken getAccessTokenOfAuthorizationCodeMode(JapHttpRequest request, OAuthConfig oAuthConfig) throws JapOauth2Exception {
|
||||
String state = request.getParameter("state");
|
||||
Oauth2Util.checkState(state, oAuthConfig.getClientId(), oAuthConfig.isVerifyState());
|
||||
|
||||
String code = request.getParameter("code");
|
||||
Map<String, String> params = new HashMap<>(6);
|
||||
params.put("grant_type", Oauth2GrantType.authorization_code.name());
|
||||
params.put("grant_type", Oauth2GrantType.AUTHORIZATION_CODE.name());
|
||||
params.put("code", code);
|
||||
params.put("client_id", oAuthConfig.getClientId());
|
||||
params.put("client_secret", oAuthConfig.getClientSecret());
|
||||
@ -101,7 +101,7 @@ public class AccessTokenHelper {
|
||||
params.put("scope", String.join(Oauth2Const.SCOPE_SEPARATOR, oAuthConfig.getScopes()));
|
||||
}
|
||||
// PKCE is only applicable to authorization code mode
|
||||
if (Oauth2ResponseType.code == oAuthConfig.getResponseType() && oAuthConfig.isEnablePkce()) {
|
||||
if (Oauth2ResponseType.CODE == oAuthConfig.getResponseType() && oAuthConfig.isEnablePkce()) {
|
||||
params.put(PkceParams.CODE_VERIFIER, PkceHelper.getCacheCodeVerifier(oAuthConfig.getClientId()));
|
||||
}
|
||||
|
||||
@ -122,7 +122,7 @@ public class AccessTokenHelper {
|
||||
* @return token request url
|
||||
* @see <a href="https://tools.ietf.org/html/rfc6749#section-4.2" target="_blank">4.2. Implicit Grant</a>
|
||||
*/
|
||||
private static AccessToken getAccessTokenOfImplicitMode(HttpServletRequest request) throws JapOauth2Exception {
|
||||
private static AccessToken getAccessTokenOfImplicitMode(JapHttpRequest request) throws JapOauth2Exception {
|
||||
Oauth2Util.checkOauthCallbackRequest(request.getParameter("error"), request.getParameter("error_description"),
|
||||
"Oauth2Strategy failed to get AccessToken.");
|
||||
|
||||
@ -148,7 +148,7 @@ public class AccessTokenHelper {
|
||||
*/
|
||||
private static AccessToken getAccessTokenOfPasswordMode(OAuthConfig oAuthConfig) throws JapOauth2Exception {
|
||||
Map<String, String> params = new HashMap<>(6);
|
||||
params.put("grant_type", Oauth2GrantType.password.name());
|
||||
params.put("grant_type", Oauth2GrantType.PASSWORD.name());
|
||||
params.put("username", oAuthConfig.getUsername());
|
||||
params.put("password", oAuthConfig.getPassword());
|
||||
params.put("client_id", oAuthConfig.getClientId());
|
||||
@ -172,7 +172,7 @@ public class AccessTokenHelper {
|
||||
* @return token request url
|
||||
* @see <a href="https://tools.ietf.org/html/rfc6749#section-4.4" target="_blank">4.4. Client Credentials Grant</a>
|
||||
*/
|
||||
private static AccessToken getAccessTokenOfClientMode(HttpServletRequest request, OAuthConfig oAuthConfig) throws JapOauth2Exception {
|
||||
private static AccessToken getAccessTokenOfClientMode(JapHttpRequest request, OAuthConfig oAuthConfig) throws JapOauth2Exception {
|
||||
throw new JapOauth2Exception("Oauth2Strategy failed to get AccessToken. Grant type of client_credentials type is not supported.");
|
||||
// Map<String, String> params = Maps.newHashMap();
|
||||
// params.put("grant_type", Oauth2GrantType.client_credentials.name());
|
||||
|
@ -16,7 +16,7 @@
|
||||
/**
|
||||
* To provide processing methods for business in OAuth authorization process, the usage is as follows:
|
||||
* <p>
|
||||
* {@link com.fujieid.jap.oauth2.token.AccessTokenHelper#getToken(HttpServletRequest, OAuthConfig, Object[])}
|
||||
* {@link com.fujieid.jap.oauth2.token.AccessTokenHelper#getToken(com.fujieid.jap.http.JapHttpRequest, OAuthConfig, Object[])}
|
||||
* According to the parameters in {@link com.fujieid.jap.oauth2.OAuthConfig}, determine which authorization mode token data to obtain
|
||||
* <p>
|
||||
* For OAuth's grant type, the following private methods are provided:
|
||||
@ -36,6 +36,5 @@
|
||||
*/
|
||||
package com.fujieid.jap.oauth2.token;
|
||||
|
||||
import com.fujieid.jap.oauth2.OAuthConfig;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import com.fujieid.jap.oauth2.OAuthConfig;
|
||||
|
@ -21,6 +21,10 @@ import com.fujieid.jap.core.cache.JapCache;
|
||||
import com.fujieid.jap.core.config.AuthenticateConfig;
|
||||
import com.fujieid.jap.core.config.JapConfig;
|
||||
import com.fujieid.jap.core.result.JapResponse;
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.http.JapHttpResponse;
|
||||
import com.fujieid.jap.http.jakarta.JakartaRequestAdapter;
|
||||
import com.fujieid.jap.http.jakarta.JakartaResponseAdapter;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@ -44,6 +48,8 @@ import static org.mockito.Mockito.when;
|
||||
*/
|
||||
public class Oauth2StrategyTest {
|
||||
|
||||
public JapHttpRequest request;
|
||||
public JapHttpResponse response;
|
||||
@Mock
|
||||
private HttpServletRequest httpServletRequestMock;
|
||||
@Mock
|
||||
@ -56,6 +62,8 @@ public class Oauth2StrategyTest {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
// Arrange
|
||||
when(httpServletRequestMock.getSession()).thenReturn(httpsSessionMock);
|
||||
this.request = new JakartaRequestAdapter(httpServletRequestMock);
|
||||
this.response = new JakartaResponseAdapter(httpServletResponseMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -99,7 +107,7 @@ public class Oauth2StrategyTest {
|
||||
JapUserService japUserService = getJapUserService();
|
||||
Oauth2Strategy oauth2Strategy = new Oauth2Strategy(japUserService, new JapConfig());
|
||||
|
||||
JapResponse response = oauth2Strategy.authenticate(null, httpServletRequestMock, httpServletResponseMock);
|
||||
JapResponse response = oauth2Strategy.authenticate(null, this.request, this.response);
|
||||
Assert.assertEquals(1005, response.getCode());
|
||||
}
|
||||
|
||||
@ -108,7 +116,7 @@ public class Oauth2StrategyTest {
|
||||
JapUserService japUserService = getJapUserService();
|
||||
Oauth2Strategy oauth2Strategy = new Oauth2Strategy(japUserService, new JapConfig());
|
||||
|
||||
JapResponse response = oauth2Strategy.authenticate(new NotOAuthConfig(), httpServletRequestMock, httpServletResponseMock);
|
||||
JapResponse response = oauth2Strategy.authenticate(new NotOAuthConfig(), this.request, this.response);
|
||||
Assert.assertEquals(500, response.getCode());
|
||||
}
|
||||
|
||||
@ -119,11 +127,11 @@ public class Oauth2StrategyTest {
|
||||
// Redirect to authorization url
|
||||
oauth2Strategy.authenticate(new OAuthConfig()
|
||||
.setTokenUrl("TokenUrl")
|
||||
.setResponseType(Oauth2ResponseType.token)
|
||||
.setResponseType(Oauth2ResponseType.TOKEN)
|
||||
.setClientSecret("ClientSecret")
|
||||
.setClientId("ClientId")
|
||||
.setAuthorizationUrl("AuthorizationUrl")
|
||||
.setUserinfoUrl("UserinfoUrl"), httpServletRequestMock, httpServletResponseMock);
|
||||
.setUserinfoUrl("UserinfoUrl"), this.request, this.response);
|
||||
}
|
||||
|
||||
private JapUserService getJapUserService() {
|
||||
|
@ -20,8 +20,9 @@ import com.fujieid.jap.core.cache.JapLocalCache;
|
||||
import com.fujieid.jap.core.context.JapAuthentication;
|
||||
import com.fujieid.jap.core.context.JapContext;
|
||||
import com.fujieid.jap.core.exception.JapOauth2Exception;
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.http.jakarta.JakartaRequestAdapter;
|
||||
import com.fujieid.jap.oauth2.pkce.PkceCodeChallengeMethod;
|
||||
import com.fujieid.jap.oauth2.token.AccessTokenHelper;
|
||||
import com.xkcoding.json.util.Kv;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
@ -40,12 +41,14 @@ import javax.servlet.http.HttpServletRequest;
|
||||
*/
|
||||
public class Oauth2UtilTest {
|
||||
|
||||
public JapHttpRequest request;
|
||||
@Mock
|
||||
private HttpServletRequest httpServletRequestMock;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
this.request = new JakartaRequestAdapter(httpServletRequestMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -189,8 +192,8 @@ public class Oauth2UtilTest {
|
||||
public void checkOauthConfigCodeResponseTypeAndGrantTypeIsNotAuthorizationCode() {
|
||||
Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig()
|
||||
.setTokenUrl("TokenUrl")
|
||||
.setResponseType(Oauth2ResponseType.code)
|
||||
.setGrantType(Oauth2GrantType.password)));
|
||||
.setResponseType(Oauth2ResponseType.CODE)
|
||||
.setGrantType(Oauth2GrantType.PASSWORD)));
|
||||
}
|
||||
|
||||
|
||||
@ -198,8 +201,8 @@ public class Oauth2UtilTest {
|
||||
public void checkOauthConfigCodeResponseTypeAndClientSecretIsNullWhenPkceIsNotEnabled() {
|
||||
Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig()
|
||||
.setTokenUrl("TokenUrl")
|
||||
.setResponseType(Oauth2ResponseType.code)
|
||||
.setGrantType(Oauth2GrantType.authorization_code)
|
||||
.setResponseType(Oauth2ResponseType.CODE)
|
||||
.setGrantType(Oauth2GrantType.AUTHORIZATION_CODE)
|
||||
.setClientSecret(null)));
|
||||
}
|
||||
|
||||
@ -208,8 +211,8 @@ public class Oauth2UtilTest {
|
||||
public void checkOauthConfigCodeResponseTypeAndClientSecretIsEmptyWhenPkceIsNotEnabled() {
|
||||
Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig()
|
||||
.setTokenUrl("TokenUrl")
|
||||
.setResponseType(Oauth2ResponseType.code)
|
||||
.setGrantType(Oauth2GrantType.authorization_code)
|
||||
.setResponseType(Oauth2ResponseType.CODE)
|
||||
.setGrantType(Oauth2GrantType.AUTHORIZATION_CODE)
|
||||
.setClientSecret("")));
|
||||
}
|
||||
|
||||
@ -218,8 +221,8 @@ public class Oauth2UtilTest {
|
||||
public void checkOauthConfigCodeResponseTypeAndClientSecretIsNullWhenPkceIsEnabled() {
|
||||
Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig()
|
||||
.setTokenUrl("TokenUrl")
|
||||
.setResponseType(Oauth2ResponseType.code)
|
||||
.setGrantType(Oauth2GrantType.authorization_code)
|
||||
.setResponseType(Oauth2ResponseType.CODE)
|
||||
.setGrantType(Oauth2GrantType.AUTHORIZATION_CODE)
|
||||
.setEnablePkce(true)
|
||||
.setClientSecret(null)));
|
||||
}
|
||||
@ -229,8 +232,8 @@ public class Oauth2UtilTest {
|
||||
public void checkOauthConfigCodeResponseTypeAndClientSecretIsEmptyWhenPkceIsEnabled() {
|
||||
Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig()
|
||||
.setTokenUrl("TokenUrl")
|
||||
.setResponseType(Oauth2ResponseType.code)
|
||||
.setGrantType(Oauth2GrantType.authorization_code)
|
||||
.setResponseType(Oauth2ResponseType.CODE)
|
||||
.setGrantType(Oauth2GrantType.AUTHORIZATION_CODE)
|
||||
.setEnablePkce(true)
|
||||
.setClientSecret("")));
|
||||
}
|
||||
@ -240,8 +243,8 @@ public class Oauth2UtilTest {
|
||||
public void checkOauthConfigCodeResponseTypeAndClientSecretIsNotEmptyWhenPkceIsEnabled() {
|
||||
Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig()
|
||||
.setTokenUrl("TokenUrl")
|
||||
.setResponseType(Oauth2ResponseType.code)
|
||||
.setGrantType(Oauth2GrantType.authorization_code)
|
||||
.setResponseType(Oauth2ResponseType.CODE)
|
||||
.setGrantType(Oauth2GrantType.AUTHORIZATION_CODE)
|
||||
.setEnablePkce(true)
|
||||
.setClientSecret("ClientSecret")));
|
||||
}
|
||||
@ -251,7 +254,7 @@ public class Oauth2UtilTest {
|
||||
public void checkOauthConfigTokenResponseTypeAndClientSecretIsEmpty() {
|
||||
Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig()
|
||||
.setTokenUrl("TokenUrl")
|
||||
.setResponseType(Oauth2ResponseType.token)
|
||||
.setResponseType(Oauth2ResponseType.TOKEN)
|
||||
.setClientSecret("")));
|
||||
}
|
||||
|
||||
@ -260,7 +263,7 @@ public class Oauth2UtilTest {
|
||||
public void checkOauthConfigTokenResponseTypeAndClientSecretIsNull() {
|
||||
Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig()
|
||||
.setTokenUrl("TokenUrl")
|
||||
.setResponseType(Oauth2ResponseType.token)
|
||||
.setResponseType(Oauth2ResponseType.TOKEN)
|
||||
.setClientSecret(null)));
|
||||
}
|
||||
|
||||
@ -269,7 +272,7 @@ public class Oauth2UtilTest {
|
||||
public void checkOauthConfigCodeOrTokenResponseTypeAndClientIdIsNull() {
|
||||
Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig()
|
||||
.setTokenUrl("TokenUrl")
|
||||
.setResponseType(Oauth2ResponseType.token)
|
||||
.setResponseType(Oauth2ResponseType.TOKEN)
|
||||
.setClientSecret("ClientSecret")
|
||||
.setClientId(null)));
|
||||
}
|
||||
@ -278,7 +281,7 @@ public class Oauth2UtilTest {
|
||||
public void checkOauthConfigCodeOrTokenResponseTypeAndClientIdIsEmpty() {
|
||||
Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig()
|
||||
.setTokenUrl("TokenUrl")
|
||||
.setResponseType(Oauth2ResponseType.token)
|
||||
.setResponseType(Oauth2ResponseType.TOKEN)
|
||||
.setClientSecret("ClientSecret")
|
||||
.setClientId("")));
|
||||
}
|
||||
@ -287,7 +290,7 @@ public class Oauth2UtilTest {
|
||||
public void checkOauthConfigCodeOrTokenResponseTypeAndAuthorizationUrlIsEmpty() {
|
||||
Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig()
|
||||
.setTokenUrl("TokenUrl")
|
||||
.setResponseType(Oauth2ResponseType.token)
|
||||
.setResponseType(Oauth2ResponseType.TOKEN)
|
||||
.setClientSecret("ClientSecret")
|
||||
.setClientId("ClientId")
|
||||
.setAuthorizationUrl("")));
|
||||
@ -297,7 +300,7 @@ public class Oauth2UtilTest {
|
||||
public void checkOauthConfigCodeOrTokenResponseTypeAndAuthorizationUrlIsNull() {
|
||||
Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig()
|
||||
.setTokenUrl("TokenUrl")
|
||||
.setResponseType(Oauth2ResponseType.token)
|
||||
.setResponseType(Oauth2ResponseType.TOKEN)
|
||||
.setClientSecret("ClientSecret")
|
||||
.setClientId("ClientId")
|
||||
.setAuthorizationUrl(null)));
|
||||
@ -307,7 +310,7 @@ public class Oauth2UtilTest {
|
||||
public void checkOauthConfigCodeOrTokenResponseTypeAndUserinfoUrlIsNull() {
|
||||
Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig()
|
||||
.setTokenUrl("TokenUrl")
|
||||
.setResponseType(Oauth2ResponseType.token)
|
||||
.setResponseType(Oauth2ResponseType.TOKEN)
|
||||
.setClientSecret("ClientSecret")
|
||||
.setClientId("ClientId")
|
||||
.setAuthorizationUrl("AuthorizationUrl")
|
||||
@ -318,7 +321,7 @@ public class Oauth2UtilTest {
|
||||
public void checkOauthConfigCodeOrTokenResponseTypeAndUserinfoUrlIsEmpty() {
|
||||
Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig()
|
||||
.setTokenUrl("TokenUrl")
|
||||
.setResponseType(Oauth2ResponseType.token)
|
||||
.setResponseType(Oauth2ResponseType.TOKEN)
|
||||
.setClientSecret("ClientSecret")
|
||||
.setClientId("ClientId")
|
||||
.setAuthorizationUrl("AuthorizationUrl")
|
||||
@ -329,7 +332,7 @@ public class Oauth2UtilTest {
|
||||
public void checkOauthConfigCodeOrTokenResponseType() {
|
||||
Oauth2Util.checkOauthConfig(new OAuthConfig()
|
||||
.setTokenUrl("TokenUrl")
|
||||
.setResponseType(Oauth2ResponseType.token)
|
||||
.setResponseType(Oauth2ResponseType.TOKEN)
|
||||
.setClientSecret("ClientSecret")
|
||||
.setClientId("ClientId")
|
||||
.setAuthorizationUrl("AuthorizationUrl")
|
||||
@ -340,43 +343,43 @@ public class Oauth2UtilTest {
|
||||
public void checkOauthConfigClientCredentialsGrantType() {
|
||||
Oauth2Util.checkOauthConfig(new OAuthConfig()
|
||||
.setTokenUrl("TokenUrl")
|
||||
.setGrantType(Oauth2GrantType.client_credentials));
|
||||
.setGrantType(Oauth2GrantType.CLIENT_CREDENTIALS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkOauthConfigPasswordGrantTypeAndNullUsernameAndPassword() {
|
||||
Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig()
|
||||
.setTokenUrl("TokenUrl")
|
||||
.setGrantType(Oauth2GrantType.password)));
|
||||
.setGrantType(Oauth2GrantType.PASSWORD)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkOauthConfigPasswordGrantTypeAndHasUsernameAndPassword() {
|
||||
Oauth2Util.checkOauthConfig(new OAuthConfig()
|
||||
.setTokenUrl("TokenUrl")
|
||||
.setGrantType(Oauth2GrantType.password)
|
||||
.setGrantType(Oauth2GrantType.PASSWORD)
|
||||
.setUsername("username")
|
||||
.setPassword("password"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isCallbackCodeResponseType() {
|
||||
boolean res = Oauth2Util.isCallback(httpServletRequestMock, new OAuthConfig()
|
||||
.setResponseType(Oauth2ResponseType.code));
|
||||
boolean res = Oauth2Util.isCallback(request, new OAuthConfig()
|
||||
.setResponseType(Oauth2ResponseType.CODE));
|
||||
Assert.assertFalse(res);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isCallbackTokenResponseType() {
|
||||
boolean res = Oauth2Util.isCallback(httpServletRequestMock, new OAuthConfig()
|
||||
.setResponseType(Oauth2ResponseType.token));
|
||||
boolean res = Oauth2Util.isCallback(request, new OAuthConfig()
|
||||
.setResponseType(Oauth2ResponseType.TOKEN));
|
||||
Assert.assertFalse(res);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isCallbackNoneResponseType() {
|
||||
boolean res = Oauth2Util.isCallback(httpServletRequestMock, new OAuthConfig()
|
||||
.setResponseType(Oauth2ResponseType.none));
|
||||
boolean res = Oauth2Util.isCallback(request, new OAuthConfig()
|
||||
.setResponseType(Oauth2ResponseType.NONE));
|
||||
Assert.assertFalse(res);
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,9 @@ import com.fujieid.jap.core.cache.JapLocalCache;
|
||||
import com.fujieid.jap.core.context.JapAuthentication;
|
||||
import com.fujieid.jap.core.context.JapContext;
|
||||
import com.fujieid.jap.core.exception.JapOauth2Exception;
|
||||
import com.fujieid.jap.core.exception.OidcException;
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.http.jakarta.JakartaRequestAdapter;
|
||||
import com.fujieid.jap.oauth2.OAuthConfig;
|
||||
import com.fujieid.jap.oauth2.Oauth2GrantType;
|
||||
import com.fujieid.jap.oauth2.Oauth2ResponseType;
|
||||
@ -40,45 +43,47 @@ import javax.servlet.http.HttpServletRequest;
|
||||
*/
|
||||
public class AccessTokenHelperTest {
|
||||
|
||||
public JapHttpRequest request;
|
||||
@Mock
|
||||
private HttpServletRequest httpServletRequestMock;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
this.request = new JakartaRequestAdapter(httpServletRequestMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTokenNullOAuthConfig() {
|
||||
Assert.assertThrows(JapOauth2Exception.class, () -> AccessTokenHelper.getToken(httpServletRequestMock, null));
|
||||
Assert.assertThrows(JapOauth2Exception.class, () -> AccessTokenHelper.getToken(request, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTokenEmptyOAuthConfig() {
|
||||
Assert.assertThrows(JapOauth2Exception.class, () -> AccessTokenHelper.getToken(httpServletRequestMock, new OAuthConfig()));
|
||||
Assert.assertThrows(JapOauth2Exception.class, () -> AccessTokenHelper.getToken(request, new OAuthConfig()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTokenCodeResponseType() {
|
||||
Assert.assertThrows(JapOauth2Exception.class, () -> AccessTokenHelper.getToken(httpServletRequestMock, new OAuthConfig()
|
||||
.setResponseType(Oauth2ResponseType.code)));
|
||||
Assert.assertThrows(JapOauth2Exception.class, () -> AccessTokenHelper.getToken(request, new OAuthConfig()
|
||||
.setResponseType(Oauth2ResponseType.CODE)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTokenCodeResponseTypeDoNotCheckState() {
|
||||
// Http url must be not blank!
|
||||
Assert.assertThrows(IllegalArgumentException.class, () -> AccessTokenHelper.getToken(httpServletRequestMock, new OAuthConfig()
|
||||
Assert.assertThrows(IllegalArgumentException.class, () -> AccessTokenHelper.getToken(request, new OAuthConfig()
|
||||
.setVerifyState(false)
|
||||
.setResponseType(Oauth2ResponseType.code)));
|
||||
.setResponseType(Oauth2ResponseType.CODE)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTokenCodeResponseTypeNullCache() {
|
||||
JapAuthentication.setContext(new JapContext());
|
||||
JapAuthentication.getContext().setCache(null);
|
||||
Assert.assertThrows(NullPointerException.class, () -> AccessTokenHelper.getToken(httpServletRequestMock, new OAuthConfig()
|
||||
Assert.assertThrows(NullPointerException.class, () -> AccessTokenHelper.getToken(request, new OAuthConfig()
|
||||
.setVerifyState(false)
|
||||
.setResponseType(Oauth2ResponseType.code)
|
||||
.setResponseType(Oauth2ResponseType.CODE)
|
||||
.setEnablePkce(true)
|
||||
.setCallbackUrl("setCallbackUrl")
|
||||
.setTokenUrl("setTokenUrl")));
|
||||
@ -89,9 +94,9 @@ public class AccessTokenHelperTest {
|
||||
// UnknownHostException: setTokenUrl
|
||||
JapAuthentication.setContext(new JapContext());
|
||||
JapAuthentication.getContext().setCache(new JapLocalCache());
|
||||
Assert.assertThrows(IORuntimeException.class, () -> AccessTokenHelper.getToken(httpServletRequestMock, new OAuthConfig()
|
||||
Assert.assertThrows(JapOauth2Exception.class, () -> AccessTokenHelper.getToken(request, new OAuthConfig()
|
||||
.setVerifyState(false)
|
||||
.setResponseType(Oauth2ResponseType.code)
|
||||
.setResponseType(Oauth2ResponseType.CODE)
|
||||
.setEnablePkce(true)
|
||||
.setCallbackUrl("setCallbackUrl")
|
||||
.setTokenUrl("setTokenUrl")));
|
||||
@ -100,23 +105,23 @@ public class AccessTokenHelperTest {
|
||||
@Test
|
||||
public void getTokenTokenResponseType() {
|
||||
// Oauth2Strategy failed to get AccessToken.
|
||||
Assert.assertThrows(JapOauth2Exception.class, () -> AccessTokenHelper.getToken(httpServletRequestMock, new OAuthConfig()
|
||||
.setResponseType(Oauth2ResponseType.token)));
|
||||
Assert.assertThrows(JapOauth2Exception.class, () -> AccessTokenHelper.getToken(request, new OAuthConfig()
|
||||
.setResponseType(Oauth2ResponseType.TOKEN)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTokenPasswordGrantTypeNullTokenUrl() {
|
||||
// Http url must be not blank!
|
||||
Assert.assertThrows(IllegalArgumentException.class, () -> AccessTokenHelper.getToken(httpServletRequestMock, new OAuthConfig()
|
||||
.setGrantType(Oauth2GrantType.password)
|
||||
Assert.assertThrows(IllegalArgumentException.class, () -> AccessTokenHelper.getToken(request, new OAuthConfig()
|
||||
.setGrantType(Oauth2GrantType.PASSWORD)
|
||||
.setScopes(new String[]{"read"})));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTokenPasswordGrantTypeErrorTokenUrl() {
|
||||
// UnknownHostException: setTokenUrl
|
||||
Assert.assertThrows(IORuntimeException.class, () -> AccessTokenHelper.getToken(httpServletRequestMock, new OAuthConfig()
|
||||
.setGrantType(Oauth2GrantType.password)
|
||||
Assert.assertThrows(JapOauth2Exception.class, () -> AccessTokenHelper.getToken(request, new OAuthConfig()
|
||||
.setGrantType(Oauth2GrantType.PASSWORD)
|
||||
.setScopes(new String[]{"read"})
|
||||
.setTokenUrl("setTokenUrl")));
|
||||
}
|
||||
@ -124,8 +129,8 @@ public class AccessTokenHelperTest {
|
||||
@Test
|
||||
public void getTokenClientCredentialsGrantTypeErrorTokenUrl() {
|
||||
// UnknownHostException: setTokenUrl
|
||||
Assert.assertThrows(JapOauth2Exception.class, () -> AccessTokenHelper.getToken(httpServletRequestMock, new OAuthConfig()
|
||||
.setGrantType(Oauth2GrantType.client_credentials)
|
||||
Assert.assertThrows(JapOauth2Exception.class, () -> AccessTokenHelper.getToken(request, new OAuthConfig()
|
||||
.setGrantType(Oauth2GrantType.CLIENT_CREDENTIALS)
|
||||
.setScopes(new String[]{"read"})
|
||||
.setTokenUrl("setTokenUrl")));
|
||||
}
|
||||
|
@ -25,12 +25,11 @@ import com.fujieid.jap.core.exception.JapException;
|
||||
import com.fujieid.jap.core.exception.OidcException;
|
||||
import com.fujieid.jap.core.result.JapErrorCode;
|
||||
import com.fujieid.jap.core.result.JapResponse;
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.http.JapHttpResponse;
|
||||
import com.fujieid.jap.oauth2.OAuthConfig;
|
||||
import com.fujieid.jap.oauth2.Oauth2Strategy;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* OpenID Connect 1.0 is a simple identity layer on top of the OAuth 2.0 protocol.
|
||||
* It enables Clients to verify the identity of the End-User based on the authentication performed by an Authorization Server,
|
||||
@ -72,7 +71,7 @@ public class OidcStrategy extends Oauth2Strategy {
|
||||
* @param response The response to authenticate
|
||||
*/
|
||||
@Override
|
||||
public JapResponse authenticate(AuthenticateConfig config, HttpServletRequest request, HttpServletResponse response) {
|
||||
public JapResponse authenticate(AuthenticateConfig config, JapHttpRequest request, JapHttpResponse response) {
|
||||
|
||||
try {
|
||||
this.checkAuthenticateConfig(config, OidcConfig.class);
|
||||
|
@ -19,6 +19,7 @@ import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.fujieid.jap.core.exception.OidcException;
|
||||
import com.xkcoding.http.HttpUtil;
|
||||
import com.xkcoding.http.support.SimpleHttpResponse;
|
||||
import com.xkcoding.json.JsonUtil;
|
||||
import com.xkcoding.json.util.Kv;
|
||||
|
||||
@ -43,13 +44,12 @@ public class OidcUtil {
|
||||
}
|
||||
String discoveryUrl = issuer.concat(DISCOVERY_URL);
|
||||
|
||||
String response = null;
|
||||
try {
|
||||
response = HttpUtil.get(discoveryUrl);
|
||||
} catch (Exception e) {
|
||||
throw new OidcException("Cannot access discovery url: " + discoveryUrl);
|
||||
SimpleHttpResponse response = HttpUtil.get(discoveryUrl);
|
||||
if(!response.isSuccess()) {
|
||||
throw new OidcException("Cannot access discovery url: " + discoveryUrl + ", " + response.getError());
|
||||
}
|
||||
Kv oidcDiscoveryInfo = JsonUtil.parseKv(response);
|
||||
|
||||
Kv oidcDiscoveryInfo = JsonUtil.parseKv(response.getBody());
|
||||
if (CollectionUtil.isEmpty(oidcDiscoveryInfo)) {
|
||||
throw new OidcException("Unable to parse IDP service discovery configuration information.");
|
||||
}
|
||||
|
@ -15,10 +15,10 @@
|
||||
*/
|
||||
package com.fujieid.jap.simple;
|
||||
|
||||
import com.fujieid.jap.core.util.RequestUtil;
|
||||
import com.fujieid.jap.http.JapHttpRequest;
|
||||
import com.fujieid.jap.http.JapHttpSession;
|
||||
import com.fujieid.jap.http.RequestUtil;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
@ -38,13 +38,13 @@ public class JapAuthenticationDetails implements Serializable {
|
||||
|
||||
private final String sessionId;
|
||||
|
||||
public JapAuthenticationDetails(HttpServletRequest request) {
|
||||
public JapAuthenticationDetails(JapHttpRequest request) {
|
||||
|
||||
this.clientIp = RequestUtil.getIp(request);
|
||||
this.remoteAddress = request.getRemoteAddr();
|
||||
this.userAgent = RequestUtil.getHeader("user-agent", request);
|
||||
this.userAgent = RequestUtil.getUa(request);
|
||||
|
||||
HttpSession session = request.getSession(false);
|
||||
JapHttpSession session = request.getSession();
|
||||
this.sessionId = (session != null) ? session.getId() : null;
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user