Merge branch 'dev'

# Conflicts:
#	pom.xml
This commit is contained in:
yadong.zhang 2021-09-22 23:12:16 +08:00
commit 85aaec76ed
110 changed files with 2699 additions and 761 deletions

View File

@ -1,6 +1,6 @@
> 为了更高效率的处理 issue、解决问题请按照如下格式填写 BUG 详情。 > 为了更高效率的处理 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一定要提供完整详细的异常堆栈。

View File

@ -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-74ae)
> - 是否参考/借鉴/复制了其他开源项目的代码?被引用的代码所属项目的 LICENSE 是否兼容 LGPL-3.0LICENSE 兼容,请参考:[开源许可证兼容性指南 - 合并/修改代码的许可证兼容性列表](https://shimo.im/docs/uL4VQaYGL2sadQOV#anchor-39f8) > - 是否参考/借鉴/复制了其他开源项目的代码?被引用的代码所属项目的 LICENSE 是否兼容 LGPL-3.0LICENSE 兼容,请参考:[开源许可证兼容性指南 - 合并/修改代码的许可证兼容性列表](https://shimo.im/docs/uL4VQaYGL2sadQOV#anchor-39f8)
> >
> 如果你的代码或者代码中新引入的依赖项与 LGPL-3.0 不兼容,非常抱歉,我们可能不会合并你的代码。 > 如果你的代码或者代码中新引入的依赖项与 LGPL-3.0 不兼容,非常抱歉,我们可能不会通过你的代码。
> >
> 最后,感谢你的关注、支持。 > 最后,感谢你的关注、支持。
@ -13,6 +13,9 @@
## 【必填】是否自测完成并提供了相关单元测试代码? ## 【必填】是否自测完成并提供了相关单元测试代码?
- [ ] 是,已经自测完成,并提供了单元测试代码,可以直接合并。
- [ ] 否,仅完成了代码,并没做测试,也没有添加单元测试。
## 【可选】关联的 Issue有则填 ## 【可选】关联的 Issue有则填

View File

@ -15,8 +15,16 @@ assignees: ''
## Environment ## 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) version(e.g. `1.0.1`):
- JustAuthPlus(JAP) Module(e.g. `jap-ids`):
### Minimal test code / Steps to reproduce the issue ### Minimal test code / Steps to reproduce the issue
1. 1.

View File

@ -12,5 +12,13 @@ assignees: ''
## Environment ## Environment
- JustAuthPlus(JAP) version(e.g. `1.0.1`): - JustAuthPlus(JAP) Module:
- JustAuthPlus(JAP) Module(e.g. `jap-ids`): - [ ] jap-ids
- [ ] jap-mfa
- [ ] jap-oauth2
- [ ] jap-oidc
- [ ] jap-simple
- [ ] jap-social
- [ ] jap-sso
- [ ] jap-core
- JustAuthPlus(JAP) version(e.g. `1.0.1`):

View File

@ -7,8 +7,14 @@ on:
workflow_dispatch: workflow_dispatch:
push: push:
branches: [ dev ] branches: [ dev ]
paths:
- src/**
- pom.xml
pull_request: pull_request:
branches: [ dev ] branches: [ dev ]
paths:
- src/**
- pom.xml
jobs: jobs:
publish: publish:
@ -30,7 +36,22 @@ jobs:
gpg-passphrase: MAVEN_GPG_PASSWORD gpg-passphrase: MAVEN_GPG_PASSWORD
gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} 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 run: mvn clean deploy -P release
env: env:
MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }} MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }}

1
.gitignore vendored
View File

@ -51,7 +51,6 @@ build/
.vscode/ .vscode/
### other ### ### other ###
/jap-simple/src/main/java/com/fujieid/jap/simple/SimpleCallback.java
/docs/bin/deploy.sh /docs/bin/deploy.sh
/jap-core/pom.xml.versionsBackup /jap-core/pom.xml.versionsBackup
/jap-oauth2/pom.xml.versionsBackup /jap-oauth2/pom.xml.versionsBackup

View File

@ -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 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)) - 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 - 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] 支持生成自定义 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)) - fix: [jap-ids] 支持自定义验证 `client_secret`适配多种场景BCrypt 等。 (Gitee[#I44032](https://gitee.com/fujieid/jap/issues/I44032))
- feat: [jap-ids] 当启用 `IdsConfig#enableDynamicIssuer` 时,支持自定义 `context-path` - feat: [jap-ids] 当启用 `IdsConfig#enableDynamicIssuer` 时,支持自定义 `context-path`

View File

@ -86,6 +86,18 @@ public interface JapUserService {
return null; 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 * Save the oauth login user information to the database and return JapUser
* <p> * <p>
@ -101,4 +113,15 @@ public interface JapUserService {
return null; 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;
}
} }

View 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;

View File

@ -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;

View File

@ -25,12 +25,12 @@ import com.fujieid.jap.core.result.JapErrorCode;
import com.fujieid.jap.core.result.JapResponse; import com.fujieid.jap.core.result.JapResponse;
import com.fujieid.jap.core.store.JapUserStore; import com.fujieid.jap.core.store.JapUserStore;
import com.fujieid.jap.core.util.JapTokenHelper; 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 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.io.Serializable;
import java.util.Date; import java.util.Date;
import java.util.Map; import java.util.Map;
@ -74,7 +74,7 @@ public class JapAuthentication implements Serializable {
* @param response current HTTP response * @param response current HTTP response
* @return JapUser * @return JapUser
*/ */
public static JapUser getUser(HttpServletRequest request, HttpServletResponse response) { public static JapUser getUser(JapHttpRequest request, JapHttpResponse response) {
if (null == context) { if (null == context) {
return null; return null;
} }
@ -107,7 +107,7 @@ public class JapAuthentication implements Serializable {
* @param response current HTTP response * @param response current HTTP response
* @return JapResponse * @return JapResponse
*/ */
public static JapResponse checkUser(HttpServletRequest request, HttpServletResponse response) { public static JapResponse checkUser(JapHttpRequest request, JapHttpResponse response) {
JapUser japUser = getUser(request, response); JapUser japUser = getUser(request, response);
if (null == japUser) { if (null == japUser) {
return JapResponse.error(JapErrorCode.NOT_LOGGED_IN); return JapResponse.error(JapErrorCode.NOT_LOGGED_IN);
@ -154,7 +154,7 @@ public class JapAuthentication implements Serializable {
* @param response current HTTP response * @param response current HTTP response
* @return boolean * @return boolean
*/ */
public static boolean logout(HttpServletRequest request, HttpServletResponse response) { public static boolean logout(JapHttpRequest request, JapHttpResponse response) {
JapUserStore japUserStore = context.getUserStore(); JapUserStore japUserStore = context.getUserStore();
if (null == japUserStore) { if (null == japUserStore) {
return false; return false;
@ -162,7 +162,7 @@ public class JapAuthentication implements Serializable {
japUserStore.remove(request, response); japUserStore.remove(request, response);
// Clear all cookie information // Clear all cookie information
Map<String, Cookie> cookieMap = RequestUtil.getCookieMap(request); Map<String, JapHttpCookie> cookieMap = RequestUtil.getCookieMap(request);
if (CollectionUtil.isNotEmpty(cookieMap)) { if (CollectionUtil.isNotEmpty(cookieMap)) {
cookieMap.forEach((key, cookie) -> { cookieMap.forEach((key, cookie) -> {
cookie.setMaxAge(0); cookie.setMaxAge(0);

View File

@ -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;

View File

@ -14,7 +14,7 @@
* limitations under the License. * 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) * @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0.0 * @version 1.0.0

View File

@ -38,6 +38,7 @@ public enum JapErrorCode {
MISS_ISSUER(1006, "OidcStrategy requires a issuer option."), MISS_ISSUER(1006, "OidcStrategy requires a issuer option."),
MISS_CREDENTIALS(1007, "Missing credentials"), 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."), 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; private final int errroCode;

View File

@ -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;

View File

@ -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;

View File

@ -16,9 +16,8 @@
package com.fujieid.jap.core.store; package com.fujieid.jap.core.store;
import com.fujieid.jap.core.JapUser; import com.fujieid.jap.core.JapUser;
import com.fujieid.jap.http.JapHttpRequest;
import javax.servlet.http.HttpServletRequest; import com.fujieid.jap.http.JapHttpResponse;
import javax.servlet.http.HttpServletResponse;
/** /**
* Save, delete and obtain the login user information.By default, based on local caching, * 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 * @param japUser User information after successful login
* @return JapUser * @return JapUser
*/ */
JapUser save(HttpServletRequest request, HttpServletResponse response, JapUser japUser); JapUser save(JapHttpRequest request, JapHttpResponse response, JapUser japUser);
/** /**
* Clear user information from cache * Clear user information from cache
@ -46,7 +45,7 @@ public interface JapUserStore {
* @param request current HTTP request * @param request current HTTP request
* @param response current HTTP response * @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, * 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 * @param response current HTTP response
* @return JapUser * @return JapUser
*/ */
JapUser get(HttpServletRequest request, HttpServletResponse response); JapUser get(JapHttpRequest request, JapHttpResponse response);
} }

View File

@ -22,10 +22,9 @@ import com.fujieid.jap.core.config.JapConfig;
import com.fujieid.jap.core.context.JapAuthentication; import com.fujieid.jap.core.context.JapAuthentication;
import com.fujieid.jap.core.util.JapTokenHelper; import com.fujieid.jap.core.util.JapTokenHelper;
import com.fujieid.jap.core.util.JapUtil; import com.fujieid.jap.core.util.JapUtil;
import com.fujieid.jap.http.JapHttpRequest;
import javax.servlet.http.HttpServletRequest; import com.fujieid.jap.http.JapHttpResponse;
import javax.servlet.http.HttpServletResponse; import com.fujieid.jap.http.JapHttpSession;
import javax.servlet.http.HttpSession;
/** /**
* @author yadong.zhang (yadong.zhang0415(a)gmail.com) * @author yadong.zhang (yadong.zhang0415(a)gmail.com)
@ -46,8 +45,8 @@ public class SessionJapUserStore implements JapUserStore {
* @return JapUser * @return JapUser
*/ */
@Override @Override
public JapUser save(HttpServletRequest request, HttpServletResponse response, JapUser japUser) { public JapUser save(JapHttpRequest request, JapHttpResponse response, JapUser japUser) {
HttpSession session = request.getSession(); JapHttpSession session = request.getSession();
JapUser newUser = BeanUtil.copyProperties(japUser, JapUser.class); JapUser newUser = BeanUtil.copyProperties(japUser, JapUser.class);
newUser.setPassword(null); newUser.setPassword(null);
session.setAttribute(JapConst.SESSION_USER_KEY, newUser); session.setAttribute(JapConst.SESSION_USER_KEY, newUser);
@ -68,7 +67,7 @@ public class SessionJapUserStore implements JapUserStore {
* @param response current HTTP response * @param response current HTTP response
*/ */
@Override @Override
public void remove(HttpServletRequest request, HttpServletResponse response) { public void remove(JapHttpRequest request, JapHttpResponse response) {
JapConfig japConfig = JapAuthentication.getContext().getConfig(); JapConfig japConfig = JapAuthentication.getContext().getConfig();
if (!japConfig.isSso()) { 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.removeAttribute(JapConst.SESSION_USER_KEY);
session.invalidate(); session.invalidate();
} }
@ -92,8 +91,8 @@ public class SessionJapUserStore implements JapUserStore {
* @return JapUser * @return JapUser
*/ */
@Override @Override
public JapUser get(HttpServletRequest request, HttpServletResponse response) { public JapUser get(JapHttpRequest request, JapHttpResponse response) {
HttpSession session = request.getSession(); JapHttpSession session = request.getSession();
return (JapUser) session.getAttribute(JapConst.SESSION_USER_KEY); return (JapUser) session.getAttribute(JapConst.SESSION_USER_KEY);
} }
} }

View File

@ -19,12 +19,11 @@ import cn.hutool.core.util.StrUtil;
import com.fujieid.jap.core.JapUser; import com.fujieid.jap.core.JapUser;
import com.fujieid.jap.core.JapUserService; import com.fujieid.jap.core.JapUserService;
import com.fujieid.jap.core.util.JapTokenHelper; 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.JapSsoHelper;
import com.fujieid.jap.sso.config.JapSsoConfig; import com.fujieid.jap.sso.config.JapSsoConfig;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/** /**
* Operation on users in SSO mode (cookie) * Operation on users in SSO mode (cookie)
* *
@ -57,7 +56,7 @@ public class SsoJapUserStore extends SessionJapUserStore {
* @return JapUser * @return JapUser
*/ */
@Override @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); String token = JapSsoHelper.login(japUser.getUserId(), japUser.getUsername(), this.japSsoConfig, request, response);
super.save(request, response, japUser); super.save(request, response, japUser);
JapTokenHelper.saveUserToken(japUser.getUserId(), token); JapTokenHelper.saveUserToken(japUser.getUserId(), token);
@ -71,7 +70,7 @@ public class SsoJapUserStore extends SessionJapUserStore {
* @param response current HTTP response * @param response current HTTP response
*/ */
@Override @Override
public void remove(HttpServletRequest request, HttpServletResponse response) { public void remove(JapHttpRequest request, JapHttpResponse response) {
JapUser japUser = this.get(request, response); JapUser japUser = this.get(request, response);
if (null != japUser) { if (null != japUser) {
JapTokenHelper.removeUserToken(japUser.getUserId()); JapTokenHelper.removeUserToken(japUser.getUserId());
@ -89,7 +88,7 @@ public class SsoJapUserStore extends SessionJapUserStore {
* @return JapUser * @return JapUser
*/ */
@Override @Override
public JapUser get(HttpServletRequest request, HttpServletResponse response) { public JapUser get(JapHttpRequest request, JapHttpResponse response) {
String userId = JapSsoHelper.checkLogin(request); String userId = JapSsoHelper.checkLogin(request);
if (StrUtil.isBlank(userId)) { if (StrUtil.isBlank(userId)) {
// The cookie has expired. Clear session content // The cookie has expired. Clear session content

View File

@ -32,11 +32,10 @@ import com.fujieid.jap.core.result.JapResponse;
import com.fujieid.jap.core.store.JapUserStore; import com.fujieid.jap.core.store.JapUserStore;
import com.fujieid.jap.core.store.SessionJapUserStore; import com.fujieid.jap.core.store.SessionJapUserStore;
import com.fujieid.jap.core.store.SsoJapUserStore; 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 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 * General policy handling methods and parameters, policies of other platforms can inherit
* {@code AbstractJapStrategy}, and override the constructor * {@code AbstractJapStrategy}, and override the constructor
@ -106,11 +105,11 @@ public abstract class AbstractJapStrategy implements JapStrategy {
* @param response current HTTP response * @param response current HTTP response
* @return boolean * @return boolean
*/ */
protected JapUser checkSession(HttpServletRequest request, HttpServletResponse response) { protected JapUser checkSession(JapHttpRequest request, JapHttpResponse response) {
return japContext.getUserStore().get(request, 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); japContext.getUserStore().save(request, response, japUser);
return JapResponse.success(japUser); return JapResponse.success(japUser);
} }

View File

@ -18,9 +18,8 @@ package com.fujieid.jap.core.strategy;
import com.fujieid.jap.core.config.AuthenticateConfig; import com.fujieid.jap.core.config.AuthenticateConfig;
import com.fujieid.jap.core.result.JapErrorCode; import com.fujieid.jap.core.result.JapErrorCode;
import com.fujieid.jap.core.result.JapResponse; import com.fujieid.jap.core.result.JapResponse;
import com.fujieid.jap.http.JapHttpRequest;
import javax.servlet.http.HttpServletRequest; import com.fujieid.jap.http.JapHttpResponse;
import javax.servlet.http.HttpServletResponse;
/** /**
* The unified implementation interface of JAP Strategy, which must be implemented for all specific business policies. * 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 * @param response The response to authenticate
* @return JapResponse * @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"); return JapResponse.error(JapErrorCode.ERROR.getErrroCode(), "JapStrategy#authenticate(AuthenticateConfig, HttpServletRequest, HttpServletResponse) must be overridden by subclass");
} }
} }

View File

@ -16,13 +16,10 @@
package com.fujieid.jap.core.util; package com.fujieid.jap.core.util;
import com.fujieid.jap.core.JapUser; 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 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 * 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."; private static final String REDIRECT_ERROR = "JAP failed to redirect via HttpServletResponse.";
@Deprecated @Deprecated
public static void redirect(String url, HttpServletResponse response) { public static void redirect(String url, JapHttpResponse response) {
redirect(url, REDIRECT_ERROR, response); redirect(url, REDIRECT_ERROR, response);
} }
@Deprecated @Deprecated
public static void redirect(String url, String errorMessage, HttpServletResponse response) { public static void redirect(String url, String errorMessage, JapHttpResponse response) {
try { response.redirect(url);
response.sendRedirect(url);
} catch (IOException ex) {
throw new JapException(errorMessage, ex);
}
} }
public static String createToken(JapUser japUser, HttpServletRequest request) { public static String createToken(JapUser japUser, JapHttpRequest request) {
return JapSsoUtil.createToken(japUser.getUserId(), japUser.getUsername(), request); return JapSsoUtil.createToken(japUser.getUserId(), japUser.getUsername(), request);
} }
} }

View File

@ -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);
}
}

View File

@ -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;

View File

@ -22,6 +22,10 @@ import com.fujieid.jap.core.cache.JapLocalCache;
import com.fujieid.jap.core.config.JapConfig; import com.fujieid.jap.core.config.JapConfig;
import com.fujieid.jap.core.result.JapResponse; import com.fujieid.jap.core.result.JapResponse;
import com.fujieid.jap.core.store.JapUserStore; 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.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -39,9 +43,14 @@ public class JapAuthenticationTest {
@Mock @Mock
public HttpServletResponse httpServletResponseMock; public HttpServletResponse httpServletResponseMock;
public JapHttpRequest request;
public JapHttpResponse response;
@Before @Before
public void init() { public void init() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
this.request = new JakartaRequestAdapter(httpServletRequestMock);
this.response = new JakartaResponseAdapter(httpServletResponseMock);
} }
@Test @Test
@ -71,7 +80,7 @@ public class JapAuthenticationTest {
JapContext japContext = new JapContext(japUserStore, japCache, japConfig); JapContext japContext = new JapContext(japUserStore, japCache, japConfig);
JapAuthentication.setContext(japContext); JapAuthentication.setContext(japContext);
JapUser japUser = JapAuthentication.getContext().getUserStore().get(httpServletRequestMock, httpServletResponseMock); JapUser japUser = JapAuthentication.getContext().getUserStore().get(request, response);
Assert.assertNull(japUser); Assert.assertNull(japUser);
} }
@ -83,8 +92,8 @@ public class JapAuthenticationTest {
JapContext japContext = new JapContext(japUserStore, japCache, japConfig); JapContext japContext = new JapContext(japUserStore, japCache, japConfig);
JapAuthentication.setContext(japContext); JapAuthentication.setContext(japContext);
JapAuthentication.getContext().getUserStore().save(httpServletRequestMock, httpServletResponseMock, new JapUser()); JapAuthentication.getContext().getUserStore().save(request, response, new JapUser());
JapUser japUser = JapAuthentication.getContext().getUserStore().get(httpServletRequestMock, httpServletResponseMock); JapUser japUser = JapAuthentication.getContext().getUserStore().get(request, response);
Assert.assertNotNull(japUser); Assert.assertNotNull(japUser);
} }
@ -96,7 +105,7 @@ public class JapAuthenticationTest {
JapContext japContext = new JapContext(japUserStore, japCache, japConfig); JapContext japContext = new JapContext(japUserStore, japCache, japConfig);
JapAuthentication.setContext(japContext); JapAuthentication.setContext(japContext);
JapUser japUser = JapAuthentication.getUser(httpServletRequestMock, httpServletResponseMock); JapUser japUser = JapAuthentication.getUser(request, response);
Assert.assertNull(japUser); Assert.assertNull(japUser);
} }
@ -108,8 +117,8 @@ public class JapAuthenticationTest {
JapContext japContext = new JapContext(japUserStore, japCache, japConfig); JapContext japContext = new JapContext(japUserStore, japCache, japConfig);
JapAuthentication.setContext(japContext); JapAuthentication.setContext(japContext);
JapResponse response = JapAuthentication.checkUser(httpServletRequestMock, httpServletResponseMock); JapResponse japResponse = JapAuthentication.checkUser(request, response);
Assert.assertEquals(response.getCode(), 401); Assert.assertEquals(japResponse.getCode(), 401);
} }
@Test @Test
@ -120,9 +129,9 @@ public class JapAuthenticationTest {
JapContext japContext = new JapContext(japUserStore, japCache, japConfig); JapContext japContext = new JapContext(japUserStore, japCache, japConfig);
JapAuthentication.setContext(japContext); JapAuthentication.setContext(japContext);
JapAuthentication.getContext().getUserStore().save(httpServletRequestMock, httpServletResponseMock, new JapUser()); JapAuthentication.getContext().getUserStore().save(request, response, new JapUser());
JapResponse response = JapAuthentication.checkUser(httpServletRequestMock, httpServletResponseMock); JapResponse japResponse = JapAuthentication.checkUser(request, response);
Assert.assertEquals(response.getCode(), 200); Assert.assertEquals(japResponse.getCode(), 200);
} }
@Test @Test
@ -195,7 +204,7 @@ public class JapAuthenticationTest {
JapContext japContext = new JapContext(japUserStore, japCache, japConfig); JapContext japContext = new JapContext(japUserStore, japCache, japConfig);
JapAuthentication.setContext(japContext); JapAuthentication.setContext(japContext);
boolean result = JapAuthentication.logout(httpServletRequestMock, httpServletResponseMock); boolean result = JapAuthentication.logout(request, response);
Assert.assertTrue(result); Assert.assertTrue(result);
} }
@ -207,7 +216,7 @@ public class JapAuthenticationTest {
JapContext japContext = new JapContext(japUserStore, japCache, japConfig); JapContext japContext = new JapContext(japUserStore, japCache, japConfig);
JapAuthentication.setContext(japContext); JapAuthentication.setContext(japContext);
boolean result = JapAuthentication.logout(httpServletRequestMock, httpServletResponseMock); boolean result = JapAuthentication.logout(request, response);
Assert.assertFalse(result); Assert.assertFalse(result);
} }
@ -224,7 +233,7 @@ public class JapAuthenticationTest {
* @return JapUser * @return JapUser
*/ */
@Override @Override
public JapUser save(HttpServletRequest request, HttpServletResponse response, JapUser japUser) { public JapUser save(JapHttpRequest request, JapHttpResponse response, JapUser japUser) {
STORE.put(USER_KEY, japUser); STORE.put(USER_KEY, japUser);
return japUser; return japUser;
} }
@ -236,7 +245,7 @@ public class JapAuthenticationTest {
* @param response current HTTP response * @param response current HTTP response
*/ */
@Override @Override
public void remove(HttpServletRequest request, HttpServletResponse response) { public void remove(JapHttpRequest request, JapHttpResponse response) {
STORE.remove(USER_KEY); STORE.remove(USER_KEY);
} }
@ -249,7 +258,7 @@ public class JapAuthenticationTest {
* @return JapUser * @return JapUser
*/ */
@Override @Override
public JapUser get(HttpServletRequest request, HttpServletResponse response) { public JapUser get(JapHttpRequest request, JapHttpResponse response) {
return (JapUser) STORE.get(USER_KEY); return (JapUser) STORE.get(USER_KEY);
} }
} }

View File

@ -16,6 +16,8 @@
package com.fujieid.jap.core.util; package com.fujieid.jap.core.util;
import com.fujieid.jap.core.JapUser; 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.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -30,9 +32,12 @@ public class JapUtilTest {
@Mock @Mock
public HttpServletRequest httpServletRequestMock; public HttpServletRequest httpServletRequestMock;
public JapHttpRequest request;
@Before @Before
public void init() { public void init() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
this.request = new JakartaRequestAdapter(httpServletRequestMock);
} }
@Test @Test
@ -41,7 +46,7 @@ public class JapUtilTest {
when(httpServletRequestMock.getHeader("user-agent")).thenReturn("ua"); when(httpServletRequestMock.getHeader("user-agent")).thenReturn("ua");
String token = JapUtil.createToken(new JapUser() String token = JapUtil.createToken(new JapUser()
.setUserId("11111") .setUserId("11111")
.setUsername("username"), httpServletRequestMock); .setUsername("username"), request);
Assert.assertNotNull(token); Assert.assertNotNull(token);
} }
} }

29
jap-http-api/pom.xml Normal file
View 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>

View File

@ -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. egBASICDIGESTBEARER.
*/
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;
}
}

View File

@ -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 Schemehttps://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);
}
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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];
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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
View 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
View 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>

View File

@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.fujieid.jap.ids.filter; package com.fujieid.jap.web.filter;
import cn.hutool.log.Log; import com.fujieid.jap.http.JapHttpRequest;
import cn.hutool.log.LogFactory; import com.fujieid.jap.http.JapHttpResponse;
import com.fujieid.jap.ids.JapIds; import com.fujieid.jap.ids.JapIds;
import com.fujieid.jap.ids.config.IdsConfig; import com.fujieid.jap.ids.config.IdsConfig;
import com.fujieid.jap.ids.pipeline.IdsPipeline; import com.fujieid.jap.ids.pipeline.IdsPipeline;
import com.xkcoding.json.util.StringUtil; import com.xkcoding.json.util.StringUtil;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@ -37,7 +35,6 @@ import java.util.List;
* @since 1.0.0 * @since 1.0.0
*/ */
public class AbstractIdsFilter { public class AbstractIdsFilter {
protected static final Log log = LogFactory.get();
protected final List<String> ignoreUrls = new ArrayList<>(); protected final List<String> ignoreUrls = new ArrayList<>();
/** /**
@ -111,8 +108,8 @@ public class AbstractIdsFilter {
if (null == idsFilterErrorPipeline) { if (null == idsFilterErrorPipeline) {
idsFilterErrorPipeline = new IdsPipeline<Object>() { idsFilterErrorPipeline = new IdsPipeline<Object>() {
@Override @Override
public void errorHandle(ServletRequest servletRequest, ServletResponse servletResponse, Throwable throwable) { public void errorHandle(JapHttpRequest request, JapHttpResponse response, Throwable throwable) {
IdsPipeline.super.errorHandle(servletRequest, servletResponse, throwable); IdsPipeline.super.errorHandle(request, response, throwable);
} }
}; };
} }

View File

@ -13,16 +13,19 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * 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.Log;
import cn.hutool.log.LogFactory; 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.JapIds;
import com.fujieid.jap.ids.pipeline.IdsPipeline; import com.fujieid.jap.ids.pipeline.IdsPipeline;
import com.fujieid.jap.ids.util.TokenUtil; import com.fujieid.jap.ids.util.TokenUtil;
import javax.servlet.*; import javax.servlet.*;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
/** /**
@ -47,12 +50,14 @@ public class IdsAccessTokenFilter extends AbstractIdsFilter implements Filter {
return; return;
} }
log.debug("{} - {}", request.getMethod(), request.getRequestURI()); log.debug("{} - {}", request.getMethod(), request.getRequestURI());
String accessToken = TokenUtil.getAccessToken(request); String accessToken = TokenUtil.getAccessToken(new JakartaRequestAdapter(request));
try { try {
TokenUtil.validateAccessToken(accessToken); TokenUtil.validateAccessToken(accessToken);
filterChain.doFilter(servletRequest, servletResponse); filterChain.doFilter(servletRequest, servletResponse);
} catch (Exception e) { } catch (Exception e) {
this.getFilterErrorPipeline(idsFilterErrorPipeline).errorHandle(servletRequest, servletResponse, e); this.getFilterErrorPipeline(idsFilterErrorPipeline)
.errorHandle(new JakartaRequestAdapter((HttpServletRequest) servletRequest),
new JakartaResponseAdapter((HttpServletResponse) servletResponse), e);
} }
} }

View File

@ -13,8 +13,10 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * 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.JapIds;
import com.fujieid.jap.ids.exception.IdsException; import com.fujieid.jap.ids.exception.IdsException;
import com.fujieid.jap.ids.model.enums.ErrorResponse; 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.*;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException; 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 { public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
IdsPipeline<Object> idsFilterErrorPipeline = JapIds.getContext().getFilterPipeline(); IdsPipeline<Object> idsFilterErrorPipeline = JapIds.getContext().getFilterPipeline();
HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletRequest request = (HttpServletRequest) servletRequest;
boolean ignored = this.isIgnoredServletPath(request); boolean ignored = this.isIgnoredServletPath(request);
if (ignored) { if (ignored) {
filterChain.doFilter(servletRequest, servletResponse); filterChain.doFilter(servletRequest, servletResponse);
return; return;
} }
if (JapIds.isAuthenticated(request)) { if (JapIds.isAuthenticated(new JakartaRequestAdapter(request))) {
filterChain.doFilter(servletRequest, servletResponse); filterChain.doFilter(servletRequest, servletResponse);
return; 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)); new IdsException(ErrorResponse.INVALID_USER_STATUS));
} }

View File

@ -20,4 +20,4 @@
* @version 1.0.0 * @version 1.0.0
* @since 1.0.0 * @since 1.0.0
*/ */
package com.fujieid.jap.ids.filter; package com.fujieid.jap.web.filter;

View File

@ -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;

View File

@ -16,6 +16,7 @@
package com.fujieid.jap.ids; package com.fujieid.jap.ids;
import com.fujieid.jap.core.spi.JapServiceLoader; 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.config.IdsConfig;
import com.fujieid.jap.ids.context.IdsContext; import com.fujieid.jap.ids.context.IdsContext;
import com.fujieid.jap.ids.exception.IdsException; 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.pipeline.IdsSignInPipeline;
import com.fujieid.jap.ids.service.*; import com.fujieid.jap.ids.service.*;
import javax.servlet.http.HttpServletRequest;
import java.io.Serializable; import java.io.Serializable;
/** /**
@ -90,21 +90,21 @@ public class JapIds implements Serializable {
return context; return context;
} }
public static boolean isAuthenticated(HttpServletRequest request) { public static boolean isAuthenticated(JapHttpRequest request) {
return null != getUserInfo(request); return null != getUserInfo(request);
} }
public static void saveUserInfo(UserInfo userInfo, HttpServletRequest request) { public static void saveUserInfo(UserInfo userInfo, JapHttpRequest request) {
IdsContext context = getContext(); IdsContext context = getContext();
context.getUserStoreService().save(userInfo, request); context.getUserStoreService().save(userInfo, request);
} }
public static UserInfo getUserInfo(HttpServletRequest request) { public static UserInfo getUserInfo(JapHttpRequest request) {
IdsContext context = getContext(); IdsContext context = getContext();
return context.getUserStoreService().get(request); return context.getUserStoreService().get(request);
} }
public static void removeUserInfo(HttpServletRequest request) { public static void removeUserInfo(JapHttpRequest request) {
IdsContext context = getContext(); IdsContext context = getContext();
context.getUserStoreService().remove(request); context.getUserStoreService().remove(request);
} }

View File

@ -15,14 +15,13 @@
*/ */
package com.fujieid.jap.ids.endpoint; 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.model.UserInfo;
import com.fujieid.jap.ids.pipeline.IdsPipeline; import com.fujieid.jap.ids.pipeline.IdsPipeline;
import com.fujieid.jap.ids.service.Oauth2Service; import com.fujieid.jap.ids.service.Oauth2Service;
import com.fujieid.jap.ids.service.Oauth2ServiceImpl; import com.fujieid.jap.ids.service.Oauth2ServiceImpl;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/** /**
* Abstract classes common to various endpoints * Abstract classes common to various endpoints
* *
@ -41,13 +40,13 @@ public abstract class AbstractEndpoint {
if (null == idsSigninPipeline) { if (null == idsSigninPipeline) {
idsSigninPipeline = new IdsPipeline<UserInfo>() { idsSigninPipeline = new IdsPipeline<UserInfo>() {
@Override @Override
public boolean preHandle(ServletRequest servletRequest, ServletResponse servletResponse) { public boolean preHandle(JapHttpRequest httpRequest, JapHttpResponse httpResponse) {
return IdsPipeline.super.preHandle(servletRequest, servletResponse); return IdsPipeline.super.preHandle(httpRequest, httpResponse);
} }
@Override @Override
public UserInfo postHandle(ServletRequest servletRequest, ServletResponse servletResponse) { public UserInfo postHandle(JapHttpRequest httpRequest, JapHttpResponse httpResponse) {
return IdsPipeline.super.postHandle(servletRequest, servletResponse); return IdsPipeline.super.postHandle(httpRequest, httpResponse);
} }
}; };
} }

View File

@ -15,6 +15,8 @@
*/ */
package com.fujieid.jap.ids.endpoint; 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.JapIds;
import com.fujieid.jap.ids.model.ClientDetail; import com.fujieid.jap.ids.model.ClientDetail;
import com.fujieid.jap.ids.model.IdsRequestParam; 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.OauthUtil;
import com.fujieid.jap.ids.util.ObjectUtils; import com.fujieid.jap.ids.util.ObjectUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.*; import java.util.*;
/** /**
@ -47,10 +48,11 @@ public class ApprovalEndpoint extends AbstractEndpoint {
* @param response current HTTP response * @param response current HTTP response
* @throws IOException IOException * @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); final String approvalContent = createConfirmPageHtml(request);
response.setContentType("text/html;charset=UTF-8"); 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 * @param request HttpServletRequest
* @return IdsResponse * @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); IdsRequestParam param = IdsRequestParamProvider.parseRequest(request);
ClientDetail clientDetail = JapIds.getContext().getClientDetailService().getByClientId(param.getClientId()); ClientDetail clientDetail = JapIds.getContext().getClientDetailService().getByClientId(param.getClientId());
OauthUtil.validClientDetail(clientDetail); OauthUtil.validClientDetail(clientDetail);
@ -80,7 +82,7 @@ public class ApprovalEndpoint extends AbstractEndpoint {
* @param request current HTTP request * @param request current HTTP request
* @return Confirm the html of the authorization page * @return Confirm the html of the authorization page
*/ */
private String createConfirmPageHtml(HttpServletRequest request) { private String createConfirmPageHtml(JapHttpRequest request) {
IdsRequestParam param = IdsRequestParamProvider.parseRequest(request); IdsRequestParam param = IdsRequestParamProvider.parseRequest(request);
String clientId = param.getClientId(); String clientId = param.getClientId();
ClientDetail clientDetail = JapIds.getContext().getClientDetailService().getByClientId(clientId); ClientDetail clientDetail = JapIds.getContext().getClientDetailService().getByClientId(clientId);
@ -132,7 +134,7 @@ public class ApprovalEndpoint extends AbstractEndpoint {
* @param request current HTTP request * @param request current HTTP request
* @return the scope list of the authorization confirmation page * @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;\">"); StringBuilder builder = new StringBuilder("<ul style=\"list-style: none;padding-inline-start: 20px;\">");
List<Map<String, Object>> scopeInfo = getScopeInfo(param); List<Map<String, Object>> scopeInfo = getScopeInfo(param);

View File

@ -16,6 +16,7 @@
package com.fujieid.jap.ids.endpoint; package com.fujieid.jap.ids.endpoint;
import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ArrayUtil;
import com.fujieid.jap.http.JapHttpRequest;
import com.fujieid.jap.ids.JapIds; import com.fujieid.jap.ids.JapIds;
import com.fujieid.jap.ids.exception.InvalidScopeException; import com.fujieid.jap.ids.exception.InvalidScopeException;
import com.fujieid.jap.ids.model.ClientDetail; 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.fujieid.jap.ids.util.OauthUtil;
import com.xkcoding.json.util.StringUtil; import com.xkcoding.json.util.StringUtil;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.Set; import java.util.Set;
@ -59,7 +59,7 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
* @return Callback url or authorization url * @return Callback url or authorization url
* @throws IOException IOException * @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); IdsRequestParam param = IdsRequestParamProvider.parseRequest(request);
ClientDetail clientDetail = JapIds.getContext().getClientDetailService().getByClientId(param.getClientId()); ClientDetail clientDetail = JapIds.getContext().getClientDetailService().getByClientId(param.getClientId());
@ -85,7 +85,7 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
* @param request current HTTP request * @param request current HTTP request
* @return Return the callback url (with parameters such as code) * @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); IdsRequestParam param = IdsRequestParamProvider.parseRequest(request);
// The scope checked by the user may be inconsistent with the scope passed in the current HTTP request // The scope checked by the user may be inconsistent with the scope passed in the current HTTP request

View File

@ -15,11 +15,10 @@
*/ */
package com.fujieid.jap.ids.endpoint; package com.fujieid.jap.ids.endpoint;
import com.fujieid.jap.http.JapHttpRequest;
import com.fujieid.jap.ids.model.OidcDiscoveryDto; import com.fujieid.jap.ids.model.OidcDiscoveryDto;
import com.fujieid.jap.ids.oidc.OidcUtil; import com.fujieid.jap.ids.oidc.OidcUtil;
import javax.servlet.http.HttpServletRequest;
/** /**
* OpenID Provider Endpoint * 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#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> * @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); return OidcUtil.getOidcDiscoveryInfo(request);
} }

View File

@ -15,12 +15,12 @@
*/ */
package com.fujieid.jap.ids.endpoint; 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.fujieid.jap.ids.model.enums.ErrorResponse;
import com.xkcoding.json.util.StringUtil; import com.xkcoding.json.util.StringUtil;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@ -51,12 +51,12 @@ public class ErrorEndpoint extends AbstractEndpoint {
* @param response current HTTP response * @param response current HTTP response
* @throws IOException IOException * @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)); ErrorResponse errorResponse = ErrorResponse.getByError(RequestUtil.getParam("error", request));
String errorPageHtml = createErrorPageHtml(errorResponse.getError(), errorResponse.getErrorDescription()); String errorPageHtml = createErrorPageHtml(errorResponse.getError(), errorResponse.getErrorDescription());
response.setContentType("text/html;charset=UTF-8"); response.setContentType("text/html;charset=UTF-8");
response.setContentLength(errorPageHtml.getBytes(StandardCharsets.UTF_8).length); 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 * @param response current HTTP response
* @throws IOException IOException * @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); String errorPageHtml = createErrorPageHtml(error, errorDescription);
response.setContentType("text/html;charset=UTF-8"); response.setContentType("text/html;charset=UTF-8");
response.setContentLength(errorPageHtml.getBytes(StandardCharsets.UTF_8).length); response.setContentLength(errorPageHtml.getBytes(StandardCharsets.UTF_8).length);
response.getWriter().write(errorPageHtml); response.write(errorPageHtml);
} }

View File

@ -17,6 +17,8 @@ package com.fujieid.jap.ids.endpoint;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; 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.JapIds;
import com.fujieid.jap.ids.exception.IdsException; import com.fujieid.jap.ids.exception.IdsException;
import com.fujieid.jap.ids.model.ClientDetail; 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.OauthUtil;
import com.fujieid.jap.ids.util.ObjectUtils; 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.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@ -53,14 +51,14 @@ public class LoginEndpoint extends AbstractEndpoint {
* @param response current HTTP response * @param response current HTTP response
* @throws IOException IOException * @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); String loginPageHtml = generateLoginPageHtml(request);
response.setContentType("text/html;charset=UTF-8"); response.setContentType("text/html;charset=UTF-8");
response.setContentLength(loginPageHtml.getBytes(StandardCharsets.UTF_8).length); 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(); StringBuilder sb = new StringBuilder();
sb.append("<!DOCTYPE html>\n" sb.append("<!DOCTYPE html>\n"
+ "<html lang=\"en\">\n" + "<html lang=\"en\">\n"
@ -98,19 +96,18 @@ public class LoginEndpoint extends AbstractEndpoint {
/** /**
* Login with account password * Login with account password
* *
* @param servletRequest current HTTP request * @param request current HTTP request
* @param servletResponse current HTTP response * @param response current HTTP response
* @return Confirm authorization page * @return Confirm authorization page
*/ */
public IdsResponse<String, String> signin(ServletRequest servletRequest, ServletResponse servletResponse) { public IdsResponse<String, String> signin(JapHttpRequest request, JapHttpResponse response) {
HttpServletRequest request = (HttpServletRequest) servletRequest;
IdsPipeline<UserInfo> idsSigninPipeline = JapIds.getContext().getSigninPipeline(); IdsPipeline<UserInfo> idsSigninPipeline = JapIds.getContext().getSigninPipeline();
idsSigninPipeline = this.getUserInfoIdsPipeline(idsSigninPipeline); 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."); throw new IdsException("IdsSigninPipeline<UserInfo>.preHandle returns false, the process is blocked.");
} }
IdsRequestParam param = IdsRequestParamProvider.parseRequest(request); IdsRequestParam param = IdsRequestParamProvider.parseRequest(request);
UserInfo userInfo = idsSigninPipeline.postHandle(request, servletResponse); UserInfo userInfo = idsSigninPipeline.postHandle(request, response);
if (null == userInfo) { if (null == userInfo) {
String username = param.getUsername(); String username = param.getUsername();
String password = param.getPassword(); String password = param.getPassword();

View File

@ -15,6 +15,8 @@
*/ */
package com.fujieid.jap.ids.endpoint; 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.JapIds;
import com.fujieid.jap.ids.exception.IdsException; import com.fujieid.jap.ids.exception.IdsException;
import com.fujieid.jap.ids.model.IdsResponse; 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.pipeline.IdsPipeline;
import com.fujieid.jap.ids.util.EndpointUtil; import com.fujieid.jap.ids.util.EndpointUtil;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
/** /**
* Logout Endpoint * Logout Endpoint
* *
@ -34,7 +33,7 @@ import javax.servlet.http.HttpServletRequest;
*/ */
public class LogoutEndpoint extends AbstractEndpoint { 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(); IdsPipeline<UserInfo> logoutPipeline = JapIds.getContext().getLogoutPipeline();
logoutPipeline = this.getUserInfoIdsPipeline(logoutPipeline); logoutPipeline = this.getUserInfoIdsPipeline(logoutPipeline);
if (!logoutPipeline.preHandle(request, response)) { if (!logoutPipeline.preHandle(request, response)) {

View File

@ -15,6 +15,7 @@
*/ */
package com.fujieid.jap.ids.endpoint; package com.fujieid.jap.ids.endpoint;
import com.fujieid.jap.http.JapHttpRequest;
import com.fujieid.jap.ids.exception.UnsupportedGrantTypeException; import com.fujieid.jap.ids.exception.UnsupportedGrantTypeException;
import com.fujieid.jap.ids.model.IdsRequestParam; import com.fujieid.jap.ids.model.IdsRequestParam;
import com.fujieid.jap.ids.model.IdsResponse; 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.fujieid.jap.ids.util.TokenUtil;
import com.xkcoding.json.util.StringUtil; 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: * Token Endpoint. According to the request parameters, to obtain different types of access tokens, refer to:
* <p> * <p>
@ -44,7 +43,7 @@ public class TokenEndpoint extends AbstractEndpoint {
private final IdsTokenProvider idsTokenProvider = new IdsTokenProvider(oauth2Service); 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); IdsRequestParam param = IdsRequestParamProvider.parseRequest(request);
if (StringUtil.isEmpty(param.getGrantType())) { if (StringUtil.isEmpty(param.getGrantType())) {
@ -65,7 +64,7 @@ public class TokenEndpoint extends AbstractEndpoint {
throw new UnsupportedGrantTypeException(ErrorResponse.UNSUPPORTED_GRANT_TYPE); throw new UnsupportedGrantTypeException(ErrorResponse.UNSUPPORTED_GRANT_TYPE);
} }
public IdsResponse<String, Object> revokeToken(HttpServletRequest request) { public IdsResponse<String, Object> revokeToken(JapHttpRequest request) {
TokenUtil.invalidateToken(request); TokenUtil.invalidateToken(request);
return new IdsResponse<>(); return new IdsResponse<>();
} }

View File

@ -15,6 +15,7 @@
*/ */
package com.fujieid.jap.ids.endpoint; package com.fujieid.jap.ids.endpoint;
import com.fujieid.jap.http.JapHttpRequest;
import com.fujieid.jap.ids.JapIds; import com.fujieid.jap.ids.JapIds;
import com.fujieid.jap.ids.exception.IdsException; import com.fujieid.jap.ids.exception.IdsException;
import com.fujieid.jap.ids.exception.InvalidTokenException; 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.fujieid.jap.ids.util.TokenUtil;
import com.xkcoding.json.JsonUtil; import com.xkcoding.json.JsonUtil;
import javax.servlet.http.HttpServletRequest;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; 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#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> * @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); String accessTokenStr = TokenUtil.getAccessToken(request);

View File

@ -14,7 +14,9 @@
* limitations under the License. * 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) * @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0.0 * @version 1.0.0

View File

@ -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;

View File

@ -18,6 +18,7 @@ package com.fujieid.jap.ids.oidc;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import com.fujieid.jap.http.JapHttpRequest;
import com.fujieid.jap.ids.JapIds; import com.fujieid.jap.ids.JapIds;
import com.fujieid.jap.ids.config.IdsConfig; import com.fujieid.jap.ids.config.IdsConfig;
import com.fujieid.jap.ids.model.IdsConsts; import com.fujieid.jap.ids.model.IdsConsts;
@ -32,7 +33,6 @@ import org.jose4j.jwk.JsonWebKey;
import org.jose4j.jwk.JsonWebKeySet; import org.jose4j.jwk.JsonWebKeySet;
import org.jose4j.jwt.ReservedClaimNames; import org.jose4j.jwt.ReservedClaimNames;
import javax.servlet.http.HttpServletRequest;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -43,14 +43,14 @@ import java.util.stream.Collectors;
*/ */
public class OidcUtil { public class OidcUtil {
public static OidcDiscoveryDto getOidcDiscoveryInfo(HttpServletRequest request) { public static OidcDiscoveryDto getOidcDiscoveryInfo(JapHttpRequest request) {
IdsConfig config = JapIds.getIdsConfig(); IdsConfig config = JapIds.getIdsConfig();
List<String> scopes = IdsScopeProvider.getScopeCodes(); List<String> scopes = IdsScopeProvider.getScopeCodes();
String issuer = EndpointUtil.getIssuer(request); String issuer = EndpointUtil.getIssuer(request);
Map<String, Object> model = new HashMap<>(); Map<String, Object> model = new HashMap<>(33);
model.put("issuer", issuer); model.put("issuer", issuer);
model.put("authorization_endpoint", EndpointUtil.getAuthorizeUrl(request)); model.put("authorization_endpoint", EndpointUtil.getAuthorizeUrl(request));
model.put("token_endpoint", EndpointUtil.getTokenUrl(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( model.put("request_object_signing_alg_values_supported", Arrays.asList(
"none", "none",
"RS256", "RS256",
"ES256" "ES256"
) )
); );
model.put("userinfo_signing_alg_values_supported", Arrays.asList( model.put("userinfo_signing_alg_values_supported", Arrays.asList(
"RS256", "RS256",
"ES256" "ES256"
) )
); );
model.put("request_parameter_supported", true); model.put("request_parameter_supported", true);
@ -95,8 +95,8 @@ public class OidcUtil {
model.put("require_request_uri_registration", false); model.put("require_request_uri_registration", false);
model.put("claims_parameter_supported", true); model.put("claims_parameter_supported", true);
model.put("id_token_signing_alg_values_supported", Arrays.asList( model.put("id_token_signing_alg_values_supported", Arrays.asList(
"RS256", "RS256",
"ES256" "ES256"
) )
); );
model.put("subject_types_supported", Collections.singletonList("public")); model.put("subject_types_supported", Collections.singletonList("public"));

View File

@ -14,7 +14,7 @@
* limitations under the License. * 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) * @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0.0 * @version 1.0.0

View File

@ -15,13 +15,14 @@
*/ */
package com.fujieid.jap.ids.pipeline; 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, * For the filter of jap-ids, a pipeline interface is provided. When an exception occurs in the filter,
* <p> * <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> * <p>
* The data in json format is returned by default: * The data in json format is returned by default:
* *
@ -32,7 +33,7 @@ import javax.servlet.ServletResponse;
* } * }
* </code> * </code>
* <p> * <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) * @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0.0 * @version 1.0.0
@ -42,50 +43,50 @@ public interface IdsFilterPipeline extends IdsPipeline<Object> {
/** /**
* Callback when the program is abnormal * Callback when the program is abnormal
* *
* @param servletRequest current HTTP request * @param request current HTTP request
* @param servletResponse current HTTP response * @param response current HTTP response
* @param throwable any exception thrown on handler execution, if any. * @param throwable any exception thrown on handler execution, if any.
*/ */
@Override @Override
default void errorHandle(ServletRequest servletRequest, ServletResponse servletResponse, Throwable throwable) { default void errorHandle(JapHttpRequest request, JapHttpResponse response, Throwable throwable) {
IdsPipeline.super.errorHandle(servletRequest, servletResponse, throwable); IdsPipeline.super.errorHandle(request, response, throwable);
} }
/** /**
* Operations before business process processing, such as initializing resources, etc. * Operations before business process processing, such as initializing resources, etc.
* *
* @param servletRequest current HTTP request * @param request current HTTP request
* @param servletResponse current HTTP response * @param response current HTTP response
* @return boolean * @return boolean
*/ */
@Deprecated @Deprecated
@Override @Override
default boolean preHandle(ServletRequest servletRequest, ServletResponse servletResponse) { default boolean preHandle(JapHttpRequest request, JapHttpResponse response) {
return IdsPipeline.super.preHandle(servletRequest, servletResponse); return IdsPipeline.super.preHandle(request, response);
} }
/** /**
* Intercept the execution of a handler * Intercept the execution of a handler
* *
* @param servletRequest current HTTP request * @param request current HTTP request
* @param servletResponse current HTTP response * @param response current HTTP response
* @return Object * @return Object
*/ */
@Deprecated @Deprecated
@Override @Override
default Object postHandle(ServletRequest servletRequest, ServletResponse servletResponse) { default Object postHandle(JapHttpRequest request, JapHttpResponse response) {
return IdsPipeline.super.postHandle(servletRequest, servletResponse); return IdsPipeline.super.postHandle(request, response);
} }
/** /**
* Callback after business process processing is completed, such as recycling resources, recording status, etc. * Callback after business process processing is completed, such as recycling resources, recording status, etc.
* *
* @param servletRequest current HTTP request * @param request current HTTP request
* @param servletResponse current HTTP response * @param response current HTTP response
*/ */
@Deprecated @Deprecated
@Override @Override
default void afterHandle(ServletRequest servletRequest, ServletResponse servletResponse) { default void afterHandle(JapHttpRequest request, JapHttpResponse response) {
IdsPipeline.super.afterHandle(servletRequest, servletResponse); IdsPipeline.super.afterHandle(request, response);
} }
} }

View File

@ -15,13 +15,12 @@
*/ */
package com.fujieid.jap.ids.pipeline; 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.exception.IdsException;
import com.fujieid.jap.ids.model.IdsResponse; import com.fujieid.jap.ids.model.IdsResponse;
import com.xkcoding.json.JsonUtil; import com.xkcoding.json.JsonUtil;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
/** /**
@ -41,57 +40,53 @@ public interface IdsPipeline<T> {
/** /**
* Callback when the program is abnormal * Callback when the program is abnormal
* *
* @param servletRequest current HTTP request * @param request current HTTP request
* @param servletResponse current HTTP response * @param response current HTTP response
* @param throwable any exception thrown on handler execution, if any. * @param throwable any exception thrown on handler execution, if any.
*/ */
default void errorHandle(ServletRequest servletRequest, ServletResponse servletResponse, Throwable throwable) { default void errorHandle(JapHttpRequest request, JapHttpResponse response, Throwable throwable) {
IdsResponse<String, Object> response = new IdsResponse<>(); IdsResponse<String, Object> idsResponse = new IdsResponse<>();
if (throwable instanceof IdsException) { if (throwable instanceof IdsException) {
IdsException idsException = (IdsException) throwable; IdsException idsException = (IdsException) throwable;
response.error(idsException.getError()) idsResponse.error(idsException.getError())
.errorDescription(idsException.getErrorDescription()); .errorDescription(idsException.getErrorDescription());
} else { } else {
response.errorDescription(throwable.getMessage()); idsResponse.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();
} }
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. * Operations before business process processing, such as initializing resources, etc.
* *
* @param servletRequest current HTTP request * @param request current HTTP request
* @param servletResponse current HTTP response * @param response current HTTP response
* @return boolean * @return boolean
*/ */
default boolean preHandle(ServletRequest servletRequest, ServletResponse servletResponse) { default boolean preHandle(JapHttpRequest request, JapHttpResponse response) {
return true; return true;
} }
/** /**
* Intercept the execution of a handler * Intercept the execution of a handler
* *
* @param servletRequest current HTTP request * @param request current HTTP request
* @param servletResponse current HTTP response * @param response current HTTP response
* @return Object * @return Object
*/ */
default T postHandle(ServletRequest servletRequest, ServletResponse servletResponse) { default T postHandle(JapHttpRequest request, JapHttpResponse response) {
return null; return null;
} }
/** /**
* Callback after business process processing is completed, such as recycling resources, recording status, etc. * Callback after business process processing is completed, such as recycling resources, recording status, etc.
* *
* @param servletRequest current HTTP request * @param request current HTTP request
* @param servletResponse current HTTP response * @param response current HTTP response
*/ */
default void afterHandle(ServletRequest servletRequest, ServletResponse servletResponse) { default void afterHandle(JapHttpRequest request, JapHttpResponse response) {
} }
} }

View File

@ -16,6 +16,7 @@
package com.fujieid.jap.ids.provider; package com.fujieid.jap.ids.provider;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import com.fujieid.jap.http.JapHttpRequest;
import com.fujieid.jap.ids.JapIds; import com.fujieid.jap.ids.JapIds;
import com.fujieid.jap.ids.config.IdsConfig; import com.fujieid.jap.ids.config.IdsConfig;
import com.fujieid.jap.ids.exception.InvalidRequestException; 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.model.enums.ErrorResponse;
import com.fujieid.jap.ids.util.ClientCertificateUtil; import com.fujieid.jap.ids.util.ClientCertificateUtil;
import javax.servlet.http.HttpServletRequest;
/** /**
* Parameter parser for oauth request * Parameter parser for oauth request
* *
@ -36,7 +35,7 @@ import javax.servlet.http.HttpServletRequest;
*/ */
public class IdsRequestParamProvider { public class IdsRequestParamProvider {
public static IdsRequestParam parseRequest(HttpServletRequest request) { public static IdsRequestParam parseRequest(JapHttpRequest request) {
if (ObjectUtil.isEmpty(request.getParameterMap())) { if (ObjectUtil.isEmpty(request.getParameterMap())) {
throw new InvalidRequestException(ErrorResponse.INVALID_REQUEST); throw new InvalidRequestException(ErrorResponse.INVALID_REQUEST);
} }

View File

@ -17,6 +17,7 @@ package com.fujieid.jap.ids.provider;
import cn.hutool.log.Log; import cn.hutool.log.Log;
import cn.hutool.log.LogFactory; import cn.hutool.log.LogFactory;
import com.fujieid.jap.http.JapHttpRequest;
import com.fujieid.jap.ids.JapIds; import com.fujieid.jap.ids.JapIds;
import com.fujieid.jap.ids.exception.IdsException; import com.fujieid.jap.ids.exception.IdsException;
import com.fujieid.jap.ids.model.*; 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.fujieid.jap.ids.util.TokenUtil;
import com.xkcoding.json.util.StringUtil; 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 * The token endpoint creates a token, and returns different token information for different authorization types
* *
@ -54,7 +53,7 @@ public class IdsTokenProvider {
* @return IdsResponse * @return IdsResponse
* @see <a href="https://tools.ietf.org/html/rfc6749#section-4.1" target="_blank">4.1. Authorization Code Grant</a> * @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()); AuthCode codeInfo = oauth2Service.validateAndGetAuthrizationCode(param.getGrantType(), param.getCode());
String scope = codeInfo.getScope(); String scope = codeInfo.getScope();
@ -93,7 +92,7 @@ public class IdsTokenProvider {
* @return IdsResponse * @return IdsResponse
* @see <a href="https://tools.ietf.org/html/rfc6749#section-4.3" target="_blank">4.3. Resource Owner Password Credentials Grant</a> * @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 username = param.getUsername();
String password = param.getPassword(); String password = param.getPassword();
String clientId = param.getClientId(); String clientId = param.getClientId();
@ -135,7 +134,7 @@ public class IdsTokenProvider {
* @return IdsResponse * @return IdsResponse
* @see <a href="https://tools.ietf.org/html/rfc6749#section-4.4" target="_blank">4.4. Client Credentials Grant</a> * @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(); String clientId = param.getClientId();
ClientDetail clientDetail = JapIds.getContext().getClientDetailService().getByClientId(clientId); ClientDetail clientDetail = JapIds.getContext().getClientDetailService().getByClientId(clientId);
@ -170,7 +169,7 @@ public class IdsTokenProvider {
* @return IdsResponse * @return IdsResponse
* @see <a href="https://tools.ietf.org/html/rfc6749#section-6" target="_blank">6. Refreshing an Access Token</a> * @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()); TokenUtil.validateRefreshToken(param.getRefreshToken());
AccessToken token = TokenUtil.getByRefreshToken(param.getRefreshToken()); AccessToken token = TokenUtil.getByRefreshToken(param.getRefreshToken());

View File

@ -15,10 +15,9 @@
*/ */
package com.fujieid.jap.ids.service; package com.fujieid.jap.ids.service;
import com.fujieid.jap.http.JapHttpRequest;
import com.fujieid.jap.ids.model.UserInfo; 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 * 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 { 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> * <p>
* Developers can implement this method to save user information in other media, such as cache, database, etc. * Developers can implement this method to save user information in other media, such as cache, database, etc.
* *
* @param userInfo User information after login * @param userInfo User information after login
* @param request current HTTP request * @param request current HTTP request
*/ */
void save(UserInfo userInfo, HttpServletRequest request); void save(UserInfo userInfo, JapHttpRequest request);
/** /**
* Get logged-in user information * Get logged-in user information
@ -44,12 +43,12 @@ public interface IdsUserStoreService {
* @param request current HTTP request * @param request current HTTP request
* @return UserInfo * @return UserInfo
*/ */
UserInfo get(HttpServletRequest request); UserInfo get(JapHttpRequest request);
/** /**
* Delete logged-in user information * Delete logged-in user information
* *
* @param request current HTTP request * @param request current HTTP request
*/ */
void remove(HttpServletRequest request); void remove(JapHttpRequest request);
} }

View File

@ -15,12 +15,10 @@
*/ */
package com.fujieid.jap.ids.service; 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.IdsConsts;
import com.fujieid.jap.ids.model.UserInfo; 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) * @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0.0 * @version 1.0.0
@ -29,7 +27,7 @@ import javax.servlet.http.HttpSession;
public class IdsUserStoreServiceImpl implements IdsUserStoreService { 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> * <p>
* Developers can implement this method to save user information in other media, such as cache, database, etc. * 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 * @param request current HTTP request
*/ */
@Override @Override
public void save(UserInfo userInfo, HttpServletRequest request) { public void save(UserInfo userInfo, JapHttpRequest request) {
request.getSession().setAttribute(IdsConsts.OAUTH_USERINFO_CACHE_KEY, userInfo); request.getSession().setAttribute(IdsConsts.OAUTH_USERINFO_CACHE_KEY, userInfo);
} }
@ -48,7 +46,7 @@ public class IdsUserStoreServiceImpl implements IdsUserStoreService {
* @return UserInfo * @return UserInfo
*/ */
@Override @Override
public UserInfo get(HttpServletRequest request) { public UserInfo get(JapHttpRequest request) {
return (UserInfo) request.getSession().getAttribute(IdsConsts.OAUTH_USERINFO_CACHE_KEY); return (UserInfo) request.getSession().getAttribute(IdsConsts.OAUTH_USERINFO_CACHE_KEY);
} }
@ -58,7 +56,7 @@ public class IdsUserStoreServiceImpl implements IdsUserStoreService {
* @param request current HTTP request * @param request current HTTP request
*/ */
@Override @Override
public void remove(HttpServletRequest request) { public void remove(JapHttpRequest request) {
request.getSession().removeAttribute(IdsConsts.OAUTH_USERINFO_CACHE_KEY); request.getSession().removeAttribute(IdsConsts.OAUTH_USERINFO_CACHE_KEY);
} }
} }

View File

@ -16,14 +16,14 @@
package com.fujieid.jap.ids.util; package com.fujieid.jap.ids.util;
import cn.hutool.core.util.ObjectUtil; 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.JapIds;
import com.fujieid.jap.ids.model.ClientCertificate; import com.fujieid.jap.ids.model.ClientCertificate;
import com.fujieid.jap.ids.model.IdsConsts; import com.fujieid.jap.ids.model.IdsConsts;
import com.fujieid.jap.ids.model.enums.ClientSecretAuthMethod; import com.fujieid.jap.ids.model.enums.ClientSecretAuthMethod;
import com.xkcoding.json.util.StringUtil; import com.xkcoding.json.util.StringUtil;
import javax.servlet.http.HttpServletRequest;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@ -36,7 +36,7 @@ import java.util.List;
*/ */
public class ClientCertificateUtil { public class ClientCertificateUtil {
public static ClientCertificate getClientCertificate(HttpServletRequest request) { public static ClientCertificate getClientCertificate(JapHttpRequest request) {
List<ClientSecretAuthMethod> clientSecretAuthMethods = JapIds.getIdsConfig().getClientSecretAuthMethods(); List<ClientSecretAuthMethod> clientSecretAuthMethods = JapIds.getIdsConfig().getClientSecretAuthMethods();
if (ObjectUtil.isEmpty(clientSecretAuthMethods)) { if (ObjectUtil.isEmpty(clientSecretAuthMethods)) {
clientSecretAuthMethods = Collections.singletonList(ClientSecretAuthMethod.ALL); clientSecretAuthMethods = Collections.singletonList(ClientSecretAuthMethod.ALL);
@ -63,13 +63,13 @@ public class ClientCertificateUtil {
return new ClientCertificate(); return new ClientCertificate();
} }
private static ClientCertificate getClientCertificateFromRequestParameter(HttpServletRequest request) { private static ClientCertificate getClientCertificateFromRequestParameter(JapHttpRequest request) {
String clientId = RequestUtil.getParam(IdsConsts.CLIENT_ID, request); String clientId = RequestUtil.getParam(IdsConsts.CLIENT_ID, request);
String clientSecret = RequestUtil.getParam(IdsConsts.CLIENT_SECRET, request); String clientSecret = RequestUtil.getParam(IdsConsts.CLIENT_SECRET, request);
return new ClientCertificate(clientId, clientSecret); 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); String authorizationHeader = RequestUtil.getHeader(IdsConsts.AUTHORIZATION_HEADER_NAME, request);
if (StringUtil.isNotEmpty(authorizationHeader)) { if (StringUtil.isNotEmpty(authorizationHeader)) {
BasicCredentials credentials = BasicCredentials.parse(authorizationHeader); BasicCredentials credentials = BasicCredentials.parse(authorizationHeader);

View File

@ -15,12 +15,12 @@
*/ */
package com.fujieid.jap.ids.util; 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.JapIds;
import com.fujieid.jap.ids.config.IdsConfig; import com.fujieid.jap.ids.config.IdsConfig;
import com.fujieid.jap.ids.exception.IdsException; import com.fujieid.jap.ids.exception.IdsException;
import javax.servlet.http.HttpServletRequest;
import java.util.Optional; import java.util.Optional;
/** /**
@ -32,7 +32,7 @@ import java.util.Optional;
*/ */
public class EndpointUtil { public class EndpointUtil {
public static String getIssuer(HttpServletRequest request) { public static String getIssuer(JapHttpRequest request) {
IdsConfig config = JapIds.getIdsConfig(); IdsConfig config = JapIds.getIdsConfig();
if (config.isEnableDynamicIssuer() && null == request) { if (config.isEnableDynamicIssuer() && null == request) {
throw new IdsException("The second-level domain name verification has been enabled, the HTTP request cannot be empty"); 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(); IdsConfig config = JapIds.getIdsConfig();
return getIssuer(request) + config.getLoginUrl(); return getIssuer(request) + config.getLoginUrl();
} }
public static String getErrorUrl(HttpServletRequest request) { public static String getErrorUrl(JapHttpRequest request) {
IdsConfig config = JapIds.getIdsConfig(); IdsConfig config = JapIds.getIdsConfig();
return getIssuer(request) + config.getErrorUrl(); return getIssuer(request) + config.getErrorUrl();
} }
public static String getAuthorizeUrl(HttpServletRequest request) { public static String getAuthorizeUrl(JapHttpRequest request) {
IdsConfig config = JapIds.getIdsConfig(); IdsConfig config = JapIds.getIdsConfig();
return getIssuer(request) + config.getAuthorizeUrl(); return getIssuer(request) + config.getAuthorizeUrl();
} }
public static String getAuthorizeAutoApproveUrl(HttpServletRequest request) { public static String getAuthorizeAutoApproveUrl(JapHttpRequest request) {
IdsConfig config = JapIds.getIdsConfig(); IdsConfig config = JapIds.getIdsConfig();
return getIssuer(request) + config.getAuthorizeAutoApproveUrl(); return getIssuer(request) + config.getAuthorizeAutoApproveUrl();
} }
public static String getTokenUrl(HttpServletRequest request) { public static String getTokenUrl(JapHttpRequest request) {
IdsConfig config = JapIds.getIdsConfig(); IdsConfig config = JapIds.getIdsConfig();
return getIssuer(request) + config.getTokenUrl(); return getIssuer(request) + config.getTokenUrl();
} }
public static String getUserinfoUrl(HttpServletRequest request) { public static String getUserinfoUrl(JapHttpRequest request) {
IdsConfig config = JapIds.getIdsConfig(); IdsConfig config = JapIds.getIdsConfig();
return getIssuer(request) + config.getUserinfoUrl(); return getIssuer(request) + config.getUserinfoUrl();
} }
public static String getRegistrationUrl(HttpServletRequest request) { public static String getRegistrationUrl(JapHttpRequest request) {
IdsConfig config = JapIds.getIdsConfig(); IdsConfig config = JapIds.getIdsConfig();
return getIssuer(request) + config.getRegistrationUrl(); return getIssuer(request) + config.getRegistrationUrl();
} }
public static String getEndSessionUrl(HttpServletRequest request) { public static String getEndSessionUrl(JapHttpRequest request) {
IdsConfig config = JapIds.getIdsConfig(); IdsConfig config = JapIds.getIdsConfig();
return getIssuer(request) + config.getEndSessionUrl(); return getIssuer(request) + config.getEndSessionUrl();
} }
public static String getCheckSessionUrl(HttpServletRequest request) { public static String getCheckSessionUrl(JapHttpRequest request) {
IdsConfig config = JapIds.getIdsConfig(); IdsConfig config = JapIds.getIdsConfig();
return getIssuer(request) + config.getCheckSessionUrl(); return getIssuer(request) + config.getCheckSessionUrl();
} }
public static String getLogoutRedirectUrl(HttpServletRequest request) { public static String getLogoutRedirectUrl(JapHttpRequest request) {
IdsConfig config = JapIds.getIdsConfig(); IdsConfig config = JapIds.getIdsConfig();
return getIssuer(request) + config.getLogoutRedirectUrl(); return getIssuer(request) + config.getLogoutRedirectUrl();
} }
public static String getJwksUrl(HttpServletRequest request) { public static String getJwksUrl(JapHttpRequest request) {
IdsConfig config = JapIds.getIdsConfig(); IdsConfig config = JapIds.getIdsConfig();
return getIssuer(request) + config.getJwksUrl(); return getIssuer(request) + config.getJwksUrl();
} }
public static String getDiscoveryUrl(HttpServletRequest request) { public static String getDiscoveryUrl(JapHttpRequest request) {
IdsConfig config = JapIds.getIdsConfig(); IdsConfig config = JapIds.getIdsConfig();
return getIssuer(request) + config.getDiscoveryUrl(); return getIssuer(request) + config.getDiscoveryUrl();
} }
public static String getLoginPageUrl(HttpServletRequest request) { public static String getLoginPageUrl(JapHttpRequest request) {
IdsConfig config = JapIds.getIdsConfig(); IdsConfig config = JapIds.getIdsConfig();
if (config.isExternalLoginPageUrl()) { if (config.isExternalLoginPageUrl()) {
return config.getLoginPageUrl(); return config.getLoginPageUrl();
@ -114,7 +114,7 @@ public class EndpointUtil {
return getIssuer(request) + config.getLoginPageUrl(); return getIssuer(request) + config.getLoginPageUrl();
} }
public static String getConfirmPageUrl(HttpServletRequest request) { public static String getConfirmPageUrl(JapHttpRequest request) {
IdsConfig config = JapIds.getIdsConfig(); IdsConfig config = JapIds.getIdsConfig();
if (config.isExternalConfirmPageUrl()) { if (config.isExternalConfirmPageUrl()) {
return config.getConfirmPageUrl(); return config.getConfirmPageUrl();

View File

@ -78,7 +78,13 @@ public class OauthUtil {
public static Set<String> validateScope(String requestScopes, String clientScopes) { public static Set<String> validateScope(String requestScopes, String clientScopes) {
if (StringUtil.isEmpty(requestScopes)) { 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); Set<String> scopes = OauthUtil.convertStrToList(requestScopes);

View File

@ -16,7 +16,8 @@
package com.fujieid.jap.ids.util; package com.fujieid.jap.ids.util;
import cn.hutool.core.util.ObjectUtil; 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.JapIds;
import com.fujieid.jap.ids.exception.IdsTokenException; import com.fujieid.jap.ids.exception.IdsTokenException;
import com.fujieid.jap.ids.exception.InvalidTokenException; 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.fujieid.jap.ids.service.IdsTokenService;
import com.xkcoding.json.util.StringUtil; import com.xkcoding.json.util.StringUtil;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@ -44,7 +44,7 @@ public class TokenUtil {
* @param request request * @param request request
* @return String * @return String
*/ */
public static String getAccessToken(HttpServletRequest request) { public static String getAccessToken(JapHttpRequest request) {
List<TokenAuthMethod> tokenAuthMethods = JapIds.getIdsConfig().getTokenAuthMethods(); List<TokenAuthMethod> tokenAuthMethods = JapIds.getIdsConfig().getTokenAuthMethods();
if (ObjectUtil.isEmpty(tokenAuthMethods)) { if (ObjectUtil.isEmpty(tokenAuthMethods)) {
tokenAuthMethods = Collections.singletonList(TokenAuthMethod.ALL); tokenAuthMethods = Collections.singletonList(TokenAuthMethod.ALL);
@ -79,7 +79,7 @@ public class TokenUtil {
return null; return null;
} }
private static String getAccessTokenFromUrl(HttpServletRequest request) { private static String getAccessTokenFromUrl(JapHttpRequest request) {
String accessToken = RequestUtil.getParam(IdsConsts.ACCESS_TOKEN, request); String accessToken = RequestUtil.getParam(IdsConsts.ACCESS_TOKEN, request);
if (StringUtil.isNotEmpty(accessToken)) { if (StringUtil.isNotEmpty(accessToken)) {
return accessToken; return accessToken;
@ -87,12 +87,12 @@ public class TokenUtil {
return null; return null;
} }
private static String getAccessTokenFromHeader(HttpServletRequest request) { private static String getAccessTokenFromHeader(JapHttpRequest request) {
String accessToken = RequestUtil.getHeader(IdsConsts.AUTHORIZATION_HEADER_NAME, request); String accessToken = RequestUtil.getHeader(IdsConsts.AUTHORIZATION_HEADER_NAME, request);
return BearerToken.parse(accessToken); return BearerToken.parse(accessToken);
} }
private static String getAccessTokenFromCookie(HttpServletRequest request) { private static String getAccessTokenFromCookie(JapHttpRequest request) {
return RequestUtil.getCookieVal(request, IdsConsts.ACCESS_TOKEN); 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); String accessTokenStr = TokenUtil.getAccessToken(request);
AccessToken accessToken = TokenUtil.getByAccessToken(accessTokenStr); AccessToken accessToken = TokenUtil.getByAccessToken(accessTokenStr);
if (null != accessToken) { if (null != accessToken) {

View File

@ -1,15 +1,15 @@
package com.fujieid.jap.ids; 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.IdsConfig;
import com.fujieid.jap.ids.config.JwtConfig; import com.fujieid.jap.ids.config.JwtConfig;
import com.fujieid.jap.ids.context.IdsContext; import com.fujieid.jap.ids.context.IdsContext;
import com.xkcoding.json.JsonUtil;
import org.junit.Before; import org.junit.Before;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSession;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@ -23,11 +23,10 @@ import static org.mockito.Mockito.when;
public class BaseIdsTest { public class BaseIdsTest {
public JapHttpRequest request;
@Mock @Mock
protected HttpServletRequest httpServletRequestMock; protected HttpServletRequest httpServletRequestMock;
@Mock @Mock
protected HttpServletResponse httpServletResponseMock;
@Mock
protected HttpSession httpsSessionMock; protected HttpSession httpsSessionMock;
protected String issuer = "http://www.baidu.com"; protected String issuer = "http://www.baidu.com";
@ -36,6 +35,7 @@ public class BaseIdsTest {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
// Arrange // Arrange
when(httpServletRequestMock.getSession()).thenReturn(httpsSessionMock); when(httpServletRequestMock.getSession()).thenReturn(httpsSessionMock);
this.request = new JakartaRequestAdapter(httpServletRequestMock);
// 注册 JAP IDS 上下文 // 注册 JAP IDS 上下文
JapIds.registerContext(new IdsContext() JapIds.registerContext(new IdsContext()

View File

@ -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));
}
}

View File

@ -15,8 +15,8 @@
*/ */
package com.fujieid.jap.ids.pipeline; package com.fujieid.jap.ids.pipeline;
import javax.servlet.ServletRequest; import com.fujieid.jap.http.JapHttpRequest;
import javax.servlet.ServletResponse; import com.fujieid.jap.http.JapHttpResponse;
/** /**
* @author yadong.zhang (yadong.zhang0415(a)gmail.com) * @author yadong.zhang (yadong.zhang0415(a)gmail.com)
@ -27,24 +27,24 @@ public class CustomizeFilterPipeline implements IdsFilterPipeline {
/** /**
* Callback when the program is abnormal * Callback when the program is abnormal
* *
* @param servletRequest current HTTP request * @param request current HTTP request
* @param servletResponse current HTTP response * @param response current HTTP response
* @param throwable any exception thrown on handler execution, if any. * @param throwable any exception thrown on handler execution, if any.
*/ */
@Override @Override
public void errorHandle(ServletRequest servletRequest, ServletResponse servletResponse, Throwable throwable) { public void errorHandle(JapHttpRequest request, JapHttpResponse response, Throwable throwable) {
System.out.println("CustomizeFilterPipeline >> errorHandle"); System.out.println("CustomizeFilterPipeline >> errorHandle");
} }
/** /**
* Operations before business process processing, such as initializing resources, etc. * Operations before business process processing, such as initializing resources, etc.
* *
* @param servletRequest current HTTP request * @param request current HTTP request
* @param servletResponse current HTTP response * @param response current HTTP response
* @return boolean * @return boolean
*/ */
@Override @Override
public boolean preHandle(ServletRequest servletRequest, ServletResponse servletResponse) { public boolean preHandle(JapHttpRequest request, JapHttpResponse response) {
System.out.println("CustomizeFilterPipeline >> preHandle"); System.out.println("CustomizeFilterPipeline >> preHandle");
return true; return true;
} }
@ -52,12 +52,12 @@ public class CustomizeFilterPipeline implements IdsFilterPipeline {
/** /**
* Intercept the execution of a handler * Intercept the execution of a handler
* *
* @param servletRequest current HTTP request * @param request current HTTP request
* @param servletResponse current HTTP response * @param response current HTTP response
* @return Object * @return Object
*/ */
@Override @Override
public Object postHandle(ServletRequest servletRequest, ServletResponse servletResponse) { public Object postHandle(JapHttpRequest request, JapHttpResponse response) {
System.out.println("CustomizeFilterPipeline >> postHandle"); System.out.println("CustomizeFilterPipeline >> postHandle");
return null; 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. * Callback after business process processing is completed, such as recycling resources, recording status, etc.
* *
* @param servletRequest current HTTP request * @param request current HTTP request
* @param servletResponse current HTTP response * @param response current HTTP response
*/ */
@Override @Override
public void afterHandle(ServletRequest servletRequest, ServletResponse servletResponse) { public void afterHandle(JapHttpRequest request, JapHttpResponse response) {
System.out.println("CustomizeFilterPipeline >> afterHandle"); System.out.println("CustomizeFilterPipeline >> afterHandle");
} }
} }

View File

@ -15,11 +15,10 @@
*/ */
package com.fujieid.jap.ids.pipeline; 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 com.fujieid.jap.ids.model.UserInfo;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/** /**
* @author yadong.zhang (yadong.zhang0415(a)gmail.com) * @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0.0 * @version 1.0.0
@ -29,24 +28,24 @@ public class CustomizeSignInPipeline implements IdsSignInPipeline {
/** /**
* Callback when the program is abnormal * Callback when the program is abnormal
* *
* @param servletRequest current HTTP request * @param request current HTTP request
* @param servletResponse current HTTP response * @param response current HTTP response
* @param throwable any exception thrown on handler execution, if any. * @param throwable any exception thrown on handler execution, if any.
*/ */
@Override @Override
public void errorHandle(ServletRequest servletRequest, ServletResponse servletResponse, Throwable throwable) { public void errorHandle(JapHttpRequest request, JapHttpResponse response, Throwable throwable) {
System.out.println("CustomizeSignInPipeline >> errorHandle"); System.out.println("CustomizeSignInPipeline >> errorHandle");
} }
/** /**
* Operations before business process processing, such as initializing resources, etc. * Operations before business process processing, such as initializing resources, etc.
* *
* @param servletRequest current HTTP request * @param request current HTTP request
* @param servletResponse current HTTP response * @param response current HTTP response
* @return boolean * @return boolean
*/ */
@Override @Override
public boolean preHandle(ServletRequest servletRequest, ServletResponse servletResponse) { public boolean preHandle(JapHttpRequest request, JapHttpResponse response) {
System.out.println("CustomizeSignInPipeline >> preHandle"); System.out.println("CustomizeSignInPipeline >> preHandle");
return true; return true;
} }
@ -54,12 +53,12 @@ public class CustomizeSignInPipeline implements IdsSignInPipeline {
/** /**
* Intercept the execution of a handler * Intercept the execution of a handler
* *
* @param servletRequest current HTTP request * @param request current HTTP request
* @param servletResponse current HTTP response * @param response current HTTP response
* @return UserInfo * @return UserInfo
*/ */
@Override @Override
public UserInfo postHandle(ServletRequest servletRequest, ServletResponse servletResponse) { public UserInfo postHandle(JapHttpRequest request, JapHttpResponse response) {
System.out.println("CustomizeSignInPipeline >> postHandle"); System.out.println("CustomizeSignInPipeline >> postHandle");
return null; 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. * Callback after business process processing is completed, such as recycling resources, recording status, etc.
* *
* @param servletRequest current HTTP request * @param request current HTTP request
* @param servletResponse current HTTP response * @param response current HTTP response
*/ */
@Override @Override
public void afterHandle(ServletRequest servletRequest, ServletResponse servletResponse) { public void afterHandle(JapHttpRequest request, JapHttpResponse response) {
System.out.println("CustomizeSignInPipeline >> afterHandle"); System.out.println("CustomizeSignInPipeline >> afterHandle");
} }
} }

View File

@ -39,7 +39,7 @@ public class IdsTokenProviderTest extends BaseIdsTest {
@Test @Test
public void generateAuthorizationCodeResponse() { public void generateAuthorizationCodeResponse() {
this.initParam(); this.initParam();
Assert.assertThrows(InvalidCodeException.class, () -> idsTokenProvider.generateAuthorizationCodeResponse(idsRequestParam, httpServletRequestMock)); Assert.assertThrows(InvalidCodeException.class, () -> idsTokenProvider.generateAuthorizationCodeResponse(idsRequestParam, request));
} }
@Test @Test
@ -47,7 +47,7 @@ public class IdsTokenProviderTest extends BaseIdsTest {
this.initParam(); this.initParam();
String code = oauth2Service.createAuthorizationCode(idsRequestParam, new UserInfo(), 100000L); String code = oauth2Service.createAuthorizationCode(idsRequestParam, new UserInfo(), 100000L);
idsRequestParam.setCode(code); idsRequestParam.setCode(code);
IdsResponse<String, Object> response = idsTokenProvider.generateAuthorizationCodeResponse(idsRequestParam, httpServletRequestMock); IdsResponse<String, Object> response = idsTokenProvider.generateAuthorizationCodeResponse(idsRequestParam, request);
System.out.println(response); System.out.println(response);
Assert.assertNotNull(response); Assert.assertNotNull(response);
} }
@ -58,7 +58,7 @@ public class IdsTokenProviderTest extends BaseIdsTest {
String code = oauth2Service.createAuthorizationCode(idsRequestParam, new UserInfo(), 100000L); String code = oauth2Service.createAuthorizationCode(idsRequestParam, new UserInfo(), 100000L);
idsRequestParam.setCode(code); idsRequestParam.setCode(code);
idsRequestParam.setClientId("asdasd"); idsRequestParam.setClientId("asdasd");
Assert.assertThrows(InvalidClientException.class, () -> idsTokenProvider.generateAuthorizationCodeResponse(idsRequestParam, httpServletRequestMock)); Assert.assertThrows(InvalidClientException.class, () -> idsTokenProvider.generateAuthorizationCodeResponse(idsRequestParam, request));
} }
@Test @Test
@ -67,7 +67,7 @@ public class IdsTokenProviderTest extends BaseIdsTest {
String code = oauth2Service.createAuthorizationCode(idsRequestParam, new UserInfo(), 100000L); String code = oauth2Service.createAuthorizationCode(idsRequestParam, new UserInfo(), 100000L);
idsRequestParam.setCode(code); idsRequestParam.setCode(code);
idsRequestParam.setGrantType("asdasd"); idsRequestParam.setGrantType("asdasd");
Assert.assertThrows(UnsupportedGrantTypeException.class, () -> idsTokenProvider.generateAuthorizationCodeResponse(idsRequestParam, httpServletRequestMock)); Assert.assertThrows(UnsupportedGrantTypeException.class, () -> idsTokenProvider.generateAuthorizationCodeResponse(idsRequestParam, request));
} }
@Test @Test
@ -76,7 +76,7 @@ public class IdsTokenProviderTest extends BaseIdsTest {
String code = oauth2Service.createAuthorizationCode(idsRequestParam, new UserInfo(), 100000L); String code = oauth2Service.createAuthorizationCode(idsRequestParam, new UserInfo(), 100000L);
idsRequestParam.setCode(code); idsRequestParam.setCode(code);
idsRequestParam.setRedirectUri("asdasd"); idsRequestParam.setRedirectUri("asdasd");
Assert.assertThrows(InvalidRedirectUriException.class, () -> idsTokenProvider.generateAuthorizationCodeResponse(idsRequestParam, httpServletRequestMock)); Assert.assertThrows(InvalidRedirectUriException.class, () -> idsTokenProvider.generateAuthorizationCodeResponse(idsRequestParam, request));
} }
@Test @Test
@ -85,7 +85,7 @@ public class IdsTokenProviderTest extends BaseIdsTest {
String code = oauth2Service.createAuthorizationCode(idsRequestParam, new UserInfo(), 100000L); String code = oauth2Service.createAuthorizationCode(idsRequestParam, new UserInfo(), 100000L);
idsRequestParam.setCode(code); idsRequestParam.setCode(code);
idsRequestParam.setClientSecret("asdasd"); idsRequestParam.setClientSecret("asdasd");
Assert.assertThrows(InvalidClientException.class, () -> idsTokenProvider.generateAuthorizationCodeResponse(idsRequestParam, httpServletRequestMock)); Assert.assertThrows(InvalidClientException.class, () -> idsTokenProvider.generateAuthorizationCodeResponse(idsRequestParam, request));
} }
@Test @Test

View File

@ -19,6 +19,7 @@ import com.fujieid.jap.core.spi.JapServiceLoader;
import com.fujieid.jap.ids.pipeline.IdsFilterPipeline; import com.fujieid.jap.ids.pipeline.IdsFilterPipeline;
import com.fujieid.jap.ids.pipeline.IdsPipeline; import com.fujieid.jap.ids.pipeline.IdsPipeline;
import com.fujieid.jap.ids.pipeline.IdsSignInPipeline; import com.fujieid.jap.ids.pipeline.IdsSignInPipeline;
import com.fujieid.jap.ids.service.IdsUserService;
import org.junit.Test; import org.junit.Test;
import java.util.List; import java.util.List;
@ -30,6 +31,16 @@ import java.util.List;
*/ */
public class ServiceLoaderTest { 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 @Test
public void loadIdsPipeline() { public void loadIdsPipeline() {
List<IdsPipeline> list = JapServiceLoader.load(IdsPipeline.class); List<IdsPipeline> list = JapServiceLoader.load(IdsPipeline.class);

View File

@ -32,6 +32,16 @@
<dependency> <dependency>
<groupId>com.warrenstrange</groupId> <groupId>com.warrenstrange</groupId>
<artifactId>googleauth</artifactId> <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> </dependency>
</dependencies> </dependencies>

View File

@ -19,10 +19,10 @@ import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.FileUtil;
import cn.hutool.log.Log; import cn.hutool.log.Log;
import cn.hutool.log.LogFactory; import cn.hutool.log.LogFactory;
import com.fujieid.jap.http.JapHttpResponse;
import com.fujieid.jap.sso.util.QrCodeUtil; import com.fujieid.jap.sso.util.QrCodeUtil;
import com.warrenstrange.googleauth.*; import com.warrenstrange.googleauth.*;
import javax.servlet.http.HttpServletResponse;
import java.awt.*; import java.awt.*;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -122,7 +122,7 @@ public class JapMfa {
* @param issuer The issuer name. This parameter cannot contain the colon (:) character. * @param issuer The issuer name. This parameter cannot contain the colon (:) character.
* @param response HttpServletResponse * @param response HttpServletResponse
*/ */
public void createOtpQrcode(String username, String issuer, HttpServletResponse response) { public void createOtpQrcode(String username, String issuer, JapHttpResponse response) {
try { try {
QrCodeUtil.generate(getTotpUrl(username, issuer), QrCodeUtil.generate(getTotpUrl(username, issuer),
mfaConfig.getQrcodeWidth(), mfaConfig.getQrcodeHeight(), mfaConfig.getQrcodeWidth(), mfaConfig.getQrcodeHeight(),

View File

@ -36,7 +36,7 @@ public class JapMfaConfig {
*/ */
private long period = 30000; private long period = 30000;
/** /**
* the crypto algorithm (HmacSHA1, HmacSHA256, HmacSHA512) * the crypto algorithm (HMACSHA1, HMACSHA256, HMACSHA512)
*/ */
private JapMfaAlgorithm algorithm = JapMfaAlgorithm.HmacSHA1; private JapMfaAlgorithm algorithm = JapMfaAlgorithm.HmacSHA1;

View File

@ -262,7 +262,7 @@ public class QrCodeUtil {
*/ */
public HashMap<EncodeHintType, Object> toHints() { public HashMap<EncodeHintType, Object> toHints() {
// 配置 // 配置
final HashMap<EncodeHintType, Object> hints = new HashMap<>(); final HashMap<EncodeHintType, Object> hints = new HashMap<>(7);
if (null != this.charset) { if (null != this.charset) {
hints.put(EncodeHintType.CHARACTER_SET, charset.toString().toLowerCase()); hints.put(EncodeHintType.CHARACTER_SET, charset.toString().toLowerCase());
} }

View File

@ -46,8 +46,8 @@ public class JapMfaTest {
private static void varifyCode(JapMfa japMfa) { private static void varifyCode(JapMfa japMfa) {
String secretKey = japMfa.getSecretKey(username); String secretKey = japMfa.getSecretKey(username);
System.out.println("1. 你需要打开生成的文件(或者将 Base64 字符串直接粘贴到浏览器地址会回车)"); System.out.println("1. 点击上方打印的URL链接");
System.out.println("2. 然后使用 OTP 工具扫描二维码"); System.out.println("2. 然后使用 OTP 工具扫描二维码(如果无法识别,请保存到本地后打开本地文件重新进行识别)");
System.out.println("3. 在控制台输入 code"); System.out.println("3. 在控制台输入 code");
Scanner scanner = new Scanner(System.in); Scanner scanner = new Scanner(System.in);
Integer consoleInput = null; Integer consoleInput = null;

View File

@ -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>), * "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>). * 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 * The scope supported by the OAuth platform
@ -98,7 +98,7 @@ public class OAuthConfig extends AuthenticateConfig {
private String state; private String state;
/** /**
* The scope supported by the OAuth platform * Whether to enable PKCE mode
*/ */
private boolean enablePkce; private boolean enablePkce;
@ -110,6 +110,11 @@ public class OAuthConfig extends AuthenticateConfig {
*/ */
private PkceCodeChallengeMethod codeChallengeMethod = PkceCodeChallengeMethod.S256; 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` * The username in `Resource Owner Password Credentials Grant`
* *
@ -124,11 +129,6 @@ public class OAuthConfig extends AuthenticateConfig {
*/ */
private String password; 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 * When {@code verifyState} is true, it will check whether the state in authorization request is consistent with that in callback request
*/ */

View File

@ -25,17 +25,17 @@ public enum Oauth2GrantType {
/** /**
* Authorization Code Grant * Authorization Code Grant
*/ */
authorization_code, AUTHORIZATION_CODE,
/** /**
* Resource Owner Password Credentials Grant * Resource Owner Password Credentials Grant
*/ */
password, PASSWORD,
/** /**
* Client Credentials Grant * Client Credentials Grant
*/ */
client_credentials, CLIENT_CREDENTIALS,
/** /**
* Refreshing an Access Token * Refreshing an Access Token
*/ */
refresh_token REFRESH_TOKEN
} }

View File

@ -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} * When authorization code mode or implicit authorization mode is not used, ResponseType needs to be set to {@code none}
*/ */
none, NONE,
/** /**
* Authorization Code Grant * Authorization Code Grant
*/ */
code, CODE,
/** /**
* Implicit Grant * Implicit Grant
*/ */
token TOKEN
} }

View File

@ -27,14 +27,14 @@ import com.fujieid.jap.core.exception.JapOauth2Exception;
import com.fujieid.jap.core.result.JapErrorCode; import com.fujieid.jap.core.result.JapErrorCode;
import com.fujieid.jap.core.result.JapResponse; import com.fujieid.jap.core.result.JapResponse;
import com.fujieid.jap.core.strategy.AbstractJapStrategy; 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.pkce.PkceHelper;
import com.fujieid.jap.oauth2.token.AccessToken; import com.fujieid.jap.oauth2.token.AccessToken;
import com.fujieid.jap.oauth2.token.AccessTokenHelper; import com.fujieid.jap.oauth2.token.AccessTokenHelper;
import com.xkcoding.json.util.Kv; import com.xkcoding.json.util.Kv;
import com.xkcoding.json.util.StringUtil; import com.xkcoding.json.util.StringUtil;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -82,7 +82,7 @@ public class Oauth2Strategy extends AbstractJapStrategy {
* @param response The response to authenticate * @param response The response to authenticate
*/ */
@Override @Override
public JapResponse authenticate(AuthenticateConfig config, HttpServletRequest request, HttpServletResponse response) { public JapResponse authenticate(AuthenticateConfig config, JapHttpRequest request, JapHttpResponse response) {
try { try {
Oauth2Util.checkOauthCallbackRequest(request.getParameter("error"), request.getParameter("error_description"), 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()); return JapResponse.error(e.getErrorCode(), e.getErrorMessage());
} }
boolean isPasswordOrClientMode = authConfig.getGrantType() == Oauth2GrantType.password boolean isPasswordOrClientMode = authConfig.getGrantType() == Oauth2GrantType.PASSWORD
|| authConfig.getGrantType() == Oauth2GrantType.client_credentials; || 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 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 // 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()); return JapResponse.error(e.getErrorCode(), e.getErrorMessage());
} }
OAuthConfig authConfig = (OAuthConfig) config; OAuthConfig authConfig = (OAuthConfig) config;
if (authConfig.getGrantType() != Oauth2GrantType.refresh_token) { if (authConfig.getGrantType() != Oauth2GrantType.REFRESH_TOKEN) {
return JapResponse.error(JapErrorCode.INVALID_GRANT_TYPE); return JapResponse.error(JapErrorCode.INVALID_GRANT_TYPE);
} }
AccessToken accessToken = null; AccessToken accessToken = null;
@ -233,8 +233,8 @@ public class Oauth2Strategy extends AbstractJapStrategy {
String url = null; String url = null;
// 4.1. Authorization Code Grant https://tools.ietf.org/html/rfc6749#section-4.1 // 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 // 4.2. Implicit Grant https://tools.ietf.org/html/rfc6749#section-4.2
if (authConfig.getResponseType() == Oauth2ResponseType.code || if (authConfig.getResponseType() == Oauth2ResponseType.CODE ||
authConfig.getResponseType() == Oauth2ResponseType.token) { authConfig.getResponseType() == Oauth2ResponseType.TOKEN) {
url = generateAuthorizationCodeGrantUrl(authConfig); url = generateAuthorizationCodeGrantUrl(authConfig);
} }
return url; return url;
@ -267,7 +267,7 @@ public class Oauth2Strategy extends AbstractJapStrategy {
params.put("state", authConfig.getState()); params.put("state", authConfig.getState());
JapAuthentication.getContext().getCache().set(Oauth2Const.STATE_CACHE_KEY.concat(authConfig.getClientId()), state); JapAuthentication.getContext().getCache().set(Oauth2Const.STATE_CACHE_KEY.concat(authConfig.getClientId()), state);
// Pkce is only applicable to authorization code mode // 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)); params.putAll(PkceHelper.generatePkceParameters(authConfig));
} }
String query = URLUtil.buildQuery(params, StandardCharsets.UTF_8); String query = URLUtil.buildQuery(params, StandardCharsets.UTF_8);

View File

@ -22,12 +22,14 @@ import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil; import cn.hutool.crypto.SecureUtil;
import com.fujieid.jap.core.context.JapAuthentication; import com.fujieid.jap.core.context.JapAuthentication;
import com.fujieid.jap.core.exception.JapOauth2Exception; 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.fujieid.jap.oauth2.pkce.PkceCodeChallengeMethod;
import com.xkcoding.http.HttpUtil; import com.xkcoding.http.HttpUtil;
import com.xkcoding.http.support.SimpleHttpResponse;
import com.xkcoding.json.JsonUtil; import com.xkcoding.json.JsonUtil;
import com.xkcoding.json.util.Kv; import com.xkcoding.json.util.Kv;
import javax.servlet.http.HttpServletRequest;
import java.io.Serializable; import java.io.Serializable;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
@ -82,7 +84,7 @@ public class Oauth2Util {
} }
if (responseKv.containsKey("error") && ObjectUtil.isNotEmpty(responseKv.get("error"))) { if (responseKv.containsKey("error") && ObjectUtil.isNotEmpty(responseKv.get("error"))) {
throw new JapOauth2Exception(Optional.ofNullable(errorMsg).orElse("") + 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 // 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.1
// refer to: https://tools.ietf.org/html/rfc6749#section-4.2 // refer to: https://tools.ietf.org/html/rfc6749#section-4.2
if (oAuthConfig.getResponseType() == Oauth2ResponseType.code || if (oAuthConfig.getResponseType() == Oauth2ResponseType.CODE ||
oAuthConfig.getResponseType() == Oauth2ResponseType.token) { oAuthConfig.getResponseType() == Oauth2ResponseType.TOKEN) {
if (oAuthConfig.getResponseType() == Oauth2ResponseType.code) { if (oAuthConfig.getResponseType() == Oauth2ResponseType.CODE) {
if (oAuthConfig.getGrantType() != Oauth2GrantType.authorization_code) { if (oAuthConfig.getGrantType() != Oauth2GrantType.AUTHORIZATION_CODE) {
throw new JapOauth2Exception("Invalid grantType `" + oAuthConfig.getGrantType() + "`. " + throw new JapOauth2Exception("Invalid grantType `" + oAuthConfig.getGrantType() + "`. " +
"When using authorization code mode, grantType must be `authorization_code`"); "When using authorization code mode, grantType must be `authorization_code`");
} }
@ -164,11 +166,11 @@ public class Oauth2Util {
// For password mode // For password mode
// refer to: https://tools.ietf.org/html/rfc6749#section-4.3 // refer to: https://tools.ietf.org/html/rfc6749#section-4.3
else { 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 " + 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()); "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())) { if (!StrUtil.isAllNotEmpty(oAuthConfig.getUsername(), oAuthConfig.getPassword())) {
throw new JapOauth2Exception("Oauth2Strategy requires username and password in password certificate grant"); throw new JapOauth2Exception("Oauth2Strategy requires username and password in password certificate grant");
} }
@ -186,11 +188,11 @@ public class Oauth2Util {
* @param oAuthConfig OAuthConfig * @param oAuthConfig OAuthConfig
* @return When true is returned, the current HTTP request is a callback request * @return When true is returned, the current HTTP request is a callback request
*/ */
public static boolean isCallback(HttpServletRequest request, OAuthConfig oAuthConfig) { public static boolean isCallback(JapHttpRequest request, OAuthConfig oAuthConfig) {
if (oAuthConfig.getResponseType() == Oauth2ResponseType.code) { if (oAuthConfig.getResponseType() == Oauth2ResponseType.CODE) {
String code = request.getParameter("code"); String code = request.getParameter("code");
return !StrUtil.isEmpty(code); return !StrUtil.isEmpty(code);
} else if (oAuthConfig.getResponseType() == Oauth2ResponseType.token) { } else if (oAuthConfig.getResponseType() == Oauth2ResponseType.TOKEN) {
String accessToken = request.getParameter("access_token"); String accessToken = request.getParameter("access_token");
return !StrUtil.isEmpty(accessToken); return !StrUtil.isEmpty(accessToken);
} }
@ -212,12 +214,20 @@ public class Oauth2Util {
*/ */
public static Kv request(Oauth2EndpointMethodType endpointMethodType, String url, Map<String, String> params) { public static Kv request(Oauth2EndpointMethodType endpointMethodType, String url, Map<String, String> params) {
String res = null; SimpleHttpResponse res = null;
if (null == endpointMethodType || Oauth2EndpointMethodType.GET == endpointMethodType) { if (null == endpointMethodType || Oauth2EndpointMethodType.GET == endpointMethodType) {
res = HttpUtil.get(url, params, false); res = HttpUtil.get(url, params, false);
} else { } else {
res = HttpUtil.post(url, params, false); 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());
} }
} }

View File

@ -19,17 +19,17 @@ import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.fujieid.jap.core.exception.JapOauth2Exception; import com.fujieid.jap.core.exception.JapOauth2Exception;
import com.fujieid.jap.core.util.JapUtil; import com.fujieid.jap.core.util.JapUtil;
import com.fujieid.jap.http.JapHttpRequest;
import com.fujieid.jap.oauth2.*; import com.fujieid.jap.oauth2.*;
import com.fujieid.jap.oauth2.pkce.PkceHelper; import com.fujieid.jap.oauth2.pkce.PkceHelper;
import com.fujieid.jap.oauth2.pkce.PkceParams; import com.fujieid.jap.oauth2.pkce.PkceParams;
import com.xkcoding.json.util.Kv; import com.xkcoding.json.util.Kv;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; 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 * for different authorization methods
* *
* @author yadong.zhang (yadong.zhang0415(a)gmail.com) * @author yadong.zhang (yadong.zhang0415(a)gmail.com)
@ -49,23 +49,23 @@ public class AccessTokenHelper {
* @param obj Optional parameters * @param obj Optional parameters
* @return AccessToken * @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) { if (null == oAuthConfig) {
throw new JapOauth2Exception("Oauth2Strategy failed to get AccessToken. OAuthConfig cannot be empty."); 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); return getAccessTokenOfAuthorizationCodeMode(request, oAuthConfig);
} }
if (oAuthConfig.getResponseType() == Oauth2ResponseType.token) { if (oAuthConfig.getResponseType() == Oauth2ResponseType.TOKEN) {
return getAccessTokenOfImplicitMode(request); return getAccessTokenOfImplicitMode(request);
} }
if (oAuthConfig.getGrantType() == Oauth2GrantType.password) { if (oAuthConfig.getGrantType() == Oauth2GrantType.PASSWORD) {
return getAccessTokenOfPasswordMode(oAuthConfig); return getAccessTokenOfPasswordMode(oAuthConfig);
} }
if (oAuthConfig.getGrantType() == Oauth2GrantType.client_credentials) { if (oAuthConfig.getGrantType() == Oauth2GrantType.CLIENT_CREDENTIALS) {
return getAccessTokenOfClientMode(request, oAuthConfig); return getAccessTokenOfClientMode(request, oAuthConfig);
} }
if (oAuthConfig.getGrantType() == Oauth2GrantType.refresh_token) { if (oAuthConfig.getGrantType() == Oauth2GrantType.REFRESH_TOKEN) {
String refreshToken = null; String refreshToken = null;
if (null == obj || obj.length == 0 || null == obj[0] || (refreshToken = String.valueOf(obj[0])).isEmpty()) { 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."); throw new JapOauth2Exception("Failed to refresh token, refresh_token is empty.");
@ -84,13 +84,13 @@ public class AccessTokenHelper {
* @return token request url * @return token request url
* @see <a href="https://tools.ietf.org/html/rfc6749#section-4.1" target="_blank">4.1. Authorization Code Grant</a> * @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"); String state = request.getParameter("state");
Oauth2Util.checkState(state, oAuthConfig.getClientId(), oAuthConfig.isVerifyState()); Oauth2Util.checkState(state, oAuthConfig.getClientId(), oAuthConfig.isVerifyState());
String code = request.getParameter("code"); String code = request.getParameter("code");
Map<String, String> params = new HashMap<>(6); 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("code", code);
params.put("client_id", oAuthConfig.getClientId()); params.put("client_id", oAuthConfig.getClientId());
params.put("client_secret", oAuthConfig.getClientSecret()); params.put("client_secret", oAuthConfig.getClientSecret());
@ -101,7 +101,7 @@ public class AccessTokenHelper {
params.put("scope", String.join(Oauth2Const.SCOPE_SEPARATOR, oAuthConfig.getScopes())); params.put("scope", String.join(Oauth2Const.SCOPE_SEPARATOR, oAuthConfig.getScopes()));
} }
// PKCE is only applicable to authorization code mode // 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())); params.put(PkceParams.CODE_VERIFIER, PkceHelper.getCacheCodeVerifier(oAuthConfig.getClientId()));
} }
@ -122,7 +122,7 @@ public class AccessTokenHelper {
* @return token request url * @return token request url
* @see <a href="https://tools.ietf.org/html/rfc6749#section-4.2" target="_blank">4.2. Implicit Grant</a> * @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"), Oauth2Util.checkOauthCallbackRequest(request.getParameter("error"), request.getParameter("error_description"),
"Oauth2Strategy failed to get AccessToken."); "Oauth2Strategy failed to get AccessToken.");
@ -148,7 +148,7 @@ public class AccessTokenHelper {
*/ */
private static AccessToken getAccessTokenOfPasswordMode(OAuthConfig oAuthConfig) throws JapOauth2Exception { private static AccessToken getAccessTokenOfPasswordMode(OAuthConfig oAuthConfig) throws JapOauth2Exception {
Map<String, String> params = new HashMap<>(6); 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("username", oAuthConfig.getUsername());
params.put("password", oAuthConfig.getPassword()); params.put("password", oAuthConfig.getPassword());
params.put("client_id", oAuthConfig.getClientId()); params.put("client_id", oAuthConfig.getClientId());
@ -172,7 +172,7 @@ public class AccessTokenHelper {
* @return token request url * @return token request url
* @see <a href="https://tools.ietf.org/html/rfc6749#section-4.4" target="_blank">4.4. Client Credentials Grant</a> * @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."); throw new JapOauth2Exception("Oauth2Strategy failed to get AccessToken. Grant type of client_credentials type is not supported.");
// Map<String, String> params = Maps.newHashMap(); // Map<String, String> params = Maps.newHashMap();
// params.put("grant_type", Oauth2GrantType.client_credentials.name()); // params.put("grant_type", Oauth2GrantType.client_credentials.name());

View File

@ -16,7 +16,7 @@
/** /**
* To provide processing methods for business in OAuth authorization process, the usage is as follows: * To provide processing methods for business in OAuth authorization process, the usage is as follows:
* <p> * <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 * According to the parameters in {@link com.fujieid.jap.oauth2.OAuthConfig}, determine which authorization mode token data to obtain
* <p> * <p>
* For OAuth's grant type, the following private methods are provided: * For OAuth's grant type, the following private methods are provided:
@ -36,6 +36,5 @@
*/ */
package com.fujieid.jap.oauth2.token; package com.fujieid.jap.oauth2.token;
import com.fujieid.jap.oauth2.OAuthConfig;
import javax.servlet.http.HttpServletRequest; import com.fujieid.jap.oauth2.OAuthConfig;

View File

@ -21,6 +21,10 @@ import com.fujieid.jap.core.cache.JapCache;
import com.fujieid.jap.core.config.AuthenticateConfig; import com.fujieid.jap.core.config.AuthenticateConfig;
import com.fujieid.jap.core.config.JapConfig; import com.fujieid.jap.core.config.JapConfig;
import com.fujieid.jap.core.result.JapResponse; 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.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -44,6 +48,8 @@ import static org.mockito.Mockito.when;
*/ */
public class Oauth2StrategyTest { public class Oauth2StrategyTest {
public JapHttpRequest request;
public JapHttpResponse response;
@Mock @Mock
private HttpServletRequest httpServletRequestMock; private HttpServletRequest httpServletRequestMock;
@Mock @Mock
@ -56,6 +62,8 @@ public class Oauth2StrategyTest {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
// Arrange // Arrange
when(httpServletRequestMock.getSession()).thenReturn(httpsSessionMock); when(httpServletRequestMock.getSession()).thenReturn(httpsSessionMock);
this.request = new JakartaRequestAdapter(httpServletRequestMock);
this.response = new JakartaResponseAdapter(httpServletResponseMock);
} }
@Test @Test
@ -99,7 +107,7 @@ public class Oauth2StrategyTest {
JapUserService japUserService = getJapUserService(); JapUserService japUserService = getJapUserService();
Oauth2Strategy oauth2Strategy = new Oauth2Strategy(japUserService, new JapConfig()); 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()); Assert.assertEquals(1005, response.getCode());
} }
@ -108,7 +116,7 @@ public class Oauth2StrategyTest {
JapUserService japUserService = getJapUserService(); JapUserService japUserService = getJapUserService();
Oauth2Strategy oauth2Strategy = new Oauth2Strategy(japUserService, new JapConfig()); 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()); Assert.assertEquals(500, response.getCode());
} }
@ -119,11 +127,11 @@ public class Oauth2StrategyTest {
// Redirect to authorization url // Redirect to authorization url
oauth2Strategy.authenticate(new OAuthConfig() oauth2Strategy.authenticate(new OAuthConfig()
.setTokenUrl("TokenUrl") .setTokenUrl("TokenUrl")
.setResponseType(Oauth2ResponseType.token) .setResponseType(Oauth2ResponseType.TOKEN)
.setClientSecret("ClientSecret") .setClientSecret("ClientSecret")
.setClientId("ClientId") .setClientId("ClientId")
.setAuthorizationUrl("AuthorizationUrl") .setAuthorizationUrl("AuthorizationUrl")
.setUserinfoUrl("UserinfoUrl"), httpServletRequestMock, httpServletResponseMock); .setUserinfoUrl("UserinfoUrl"), this.request, this.response);
} }
private JapUserService getJapUserService() { private JapUserService getJapUserService() {

View File

@ -20,8 +20,9 @@ import com.fujieid.jap.core.cache.JapLocalCache;
import com.fujieid.jap.core.context.JapAuthentication; import com.fujieid.jap.core.context.JapAuthentication;
import com.fujieid.jap.core.context.JapContext; import com.fujieid.jap.core.context.JapContext;
import com.fujieid.jap.core.exception.JapOauth2Exception; 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.pkce.PkceCodeChallengeMethod;
import com.fujieid.jap.oauth2.token.AccessTokenHelper;
import com.xkcoding.json.util.Kv; import com.xkcoding.json.util.Kv;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
@ -40,12 +41,14 @@ import javax.servlet.http.HttpServletRequest;
*/ */
public class Oauth2UtilTest { public class Oauth2UtilTest {
public JapHttpRequest request;
@Mock @Mock
private HttpServletRequest httpServletRequestMock; private HttpServletRequest httpServletRequestMock;
@Before @Before
public void init() { public void init() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
this.request = new JakartaRequestAdapter(httpServletRequestMock);
} }
@Test @Test
@ -189,8 +192,8 @@ public class Oauth2UtilTest {
public void checkOauthConfigCodeResponseTypeAndGrantTypeIsNotAuthorizationCode() { public void checkOauthConfigCodeResponseTypeAndGrantTypeIsNotAuthorizationCode() {
Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig() Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig()
.setTokenUrl("TokenUrl") .setTokenUrl("TokenUrl")
.setResponseType(Oauth2ResponseType.code) .setResponseType(Oauth2ResponseType.CODE)
.setGrantType(Oauth2GrantType.password))); .setGrantType(Oauth2GrantType.PASSWORD)));
} }
@ -198,8 +201,8 @@ public class Oauth2UtilTest {
public void checkOauthConfigCodeResponseTypeAndClientSecretIsNullWhenPkceIsNotEnabled() { public void checkOauthConfigCodeResponseTypeAndClientSecretIsNullWhenPkceIsNotEnabled() {
Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig() Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig()
.setTokenUrl("TokenUrl") .setTokenUrl("TokenUrl")
.setResponseType(Oauth2ResponseType.code) .setResponseType(Oauth2ResponseType.CODE)
.setGrantType(Oauth2GrantType.authorization_code) .setGrantType(Oauth2GrantType.AUTHORIZATION_CODE)
.setClientSecret(null))); .setClientSecret(null)));
} }
@ -208,8 +211,8 @@ public class Oauth2UtilTest {
public void checkOauthConfigCodeResponseTypeAndClientSecretIsEmptyWhenPkceIsNotEnabled() { public void checkOauthConfigCodeResponseTypeAndClientSecretIsEmptyWhenPkceIsNotEnabled() {
Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig() Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig()
.setTokenUrl("TokenUrl") .setTokenUrl("TokenUrl")
.setResponseType(Oauth2ResponseType.code) .setResponseType(Oauth2ResponseType.CODE)
.setGrantType(Oauth2GrantType.authorization_code) .setGrantType(Oauth2GrantType.AUTHORIZATION_CODE)
.setClientSecret(""))); .setClientSecret("")));
} }
@ -218,8 +221,8 @@ public class Oauth2UtilTest {
public void checkOauthConfigCodeResponseTypeAndClientSecretIsNullWhenPkceIsEnabled() { public void checkOauthConfigCodeResponseTypeAndClientSecretIsNullWhenPkceIsEnabled() {
Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig() Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig()
.setTokenUrl("TokenUrl") .setTokenUrl("TokenUrl")
.setResponseType(Oauth2ResponseType.code) .setResponseType(Oauth2ResponseType.CODE)
.setGrantType(Oauth2GrantType.authorization_code) .setGrantType(Oauth2GrantType.AUTHORIZATION_CODE)
.setEnablePkce(true) .setEnablePkce(true)
.setClientSecret(null))); .setClientSecret(null)));
} }
@ -229,8 +232,8 @@ public class Oauth2UtilTest {
public void checkOauthConfigCodeResponseTypeAndClientSecretIsEmptyWhenPkceIsEnabled() { public void checkOauthConfigCodeResponseTypeAndClientSecretIsEmptyWhenPkceIsEnabled() {
Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig() Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig()
.setTokenUrl("TokenUrl") .setTokenUrl("TokenUrl")
.setResponseType(Oauth2ResponseType.code) .setResponseType(Oauth2ResponseType.CODE)
.setGrantType(Oauth2GrantType.authorization_code) .setGrantType(Oauth2GrantType.AUTHORIZATION_CODE)
.setEnablePkce(true) .setEnablePkce(true)
.setClientSecret(""))); .setClientSecret("")));
} }
@ -240,8 +243,8 @@ public class Oauth2UtilTest {
public void checkOauthConfigCodeResponseTypeAndClientSecretIsNotEmptyWhenPkceIsEnabled() { public void checkOauthConfigCodeResponseTypeAndClientSecretIsNotEmptyWhenPkceIsEnabled() {
Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig() Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig()
.setTokenUrl("TokenUrl") .setTokenUrl("TokenUrl")
.setResponseType(Oauth2ResponseType.code) .setResponseType(Oauth2ResponseType.CODE)
.setGrantType(Oauth2GrantType.authorization_code) .setGrantType(Oauth2GrantType.AUTHORIZATION_CODE)
.setEnablePkce(true) .setEnablePkce(true)
.setClientSecret("ClientSecret"))); .setClientSecret("ClientSecret")));
} }
@ -251,7 +254,7 @@ public class Oauth2UtilTest {
public void checkOauthConfigTokenResponseTypeAndClientSecretIsEmpty() { public void checkOauthConfigTokenResponseTypeAndClientSecretIsEmpty() {
Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig() Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig()
.setTokenUrl("TokenUrl") .setTokenUrl("TokenUrl")
.setResponseType(Oauth2ResponseType.token) .setResponseType(Oauth2ResponseType.TOKEN)
.setClientSecret(""))); .setClientSecret("")));
} }
@ -260,7 +263,7 @@ public class Oauth2UtilTest {
public void checkOauthConfigTokenResponseTypeAndClientSecretIsNull() { public void checkOauthConfigTokenResponseTypeAndClientSecretIsNull() {
Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig() Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig()
.setTokenUrl("TokenUrl") .setTokenUrl("TokenUrl")
.setResponseType(Oauth2ResponseType.token) .setResponseType(Oauth2ResponseType.TOKEN)
.setClientSecret(null))); .setClientSecret(null)));
} }
@ -269,7 +272,7 @@ public class Oauth2UtilTest {
public void checkOauthConfigCodeOrTokenResponseTypeAndClientIdIsNull() { public void checkOauthConfigCodeOrTokenResponseTypeAndClientIdIsNull() {
Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig() Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig()
.setTokenUrl("TokenUrl") .setTokenUrl("TokenUrl")
.setResponseType(Oauth2ResponseType.token) .setResponseType(Oauth2ResponseType.TOKEN)
.setClientSecret("ClientSecret") .setClientSecret("ClientSecret")
.setClientId(null))); .setClientId(null)));
} }
@ -278,7 +281,7 @@ public class Oauth2UtilTest {
public void checkOauthConfigCodeOrTokenResponseTypeAndClientIdIsEmpty() { public void checkOauthConfigCodeOrTokenResponseTypeAndClientIdIsEmpty() {
Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig() Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig()
.setTokenUrl("TokenUrl") .setTokenUrl("TokenUrl")
.setResponseType(Oauth2ResponseType.token) .setResponseType(Oauth2ResponseType.TOKEN)
.setClientSecret("ClientSecret") .setClientSecret("ClientSecret")
.setClientId(""))); .setClientId("")));
} }
@ -287,7 +290,7 @@ public class Oauth2UtilTest {
public void checkOauthConfigCodeOrTokenResponseTypeAndAuthorizationUrlIsEmpty() { public void checkOauthConfigCodeOrTokenResponseTypeAndAuthorizationUrlIsEmpty() {
Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig() Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig()
.setTokenUrl("TokenUrl") .setTokenUrl("TokenUrl")
.setResponseType(Oauth2ResponseType.token) .setResponseType(Oauth2ResponseType.TOKEN)
.setClientSecret("ClientSecret") .setClientSecret("ClientSecret")
.setClientId("ClientId") .setClientId("ClientId")
.setAuthorizationUrl(""))); .setAuthorizationUrl("")));
@ -297,7 +300,7 @@ public class Oauth2UtilTest {
public void checkOauthConfigCodeOrTokenResponseTypeAndAuthorizationUrlIsNull() { public void checkOauthConfigCodeOrTokenResponseTypeAndAuthorizationUrlIsNull() {
Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig() Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig()
.setTokenUrl("TokenUrl") .setTokenUrl("TokenUrl")
.setResponseType(Oauth2ResponseType.token) .setResponseType(Oauth2ResponseType.TOKEN)
.setClientSecret("ClientSecret") .setClientSecret("ClientSecret")
.setClientId("ClientId") .setClientId("ClientId")
.setAuthorizationUrl(null))); .setAuthorizationUrl(null)));
@ -307,7 +310,7 @@ public class Oauth2UtilTest {
public void checkOauthConfigCodeOrTokenResponseTypeAndUserinfoUrlIsNull() { public void checkOauthConfigCodeOrTokenResponseTypeAndUserinfoUrlIsNull() {
Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig() Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig()
.setTokenUrl("TokenUrl") .setTokenUrl("TokenUrl")
.setResponseType(Oauth2ResponseType.token) .setResponseType(Oauth2ResponseType.TOKEN)
.setClientSecret("ClientSecret") .setClientSecret("ClientSecret")
.setClientId("ClientId") .setClientId("ClientId")
.setAuthorizationUrl("AuthorizationUrl") .setAuthorizationUrl("AuthorizationUrl")
@ -318,7 +321,7 @@ public class Oauth2UtilTest {
public void checkOauthConfigCodeOrTokenResponseTypeAndUserinfoUrlIsEmpty() { public void checkOauthConfigCodeOrTokenResponseTypeAndUserinfoUrlIsEmpty() {
Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig() Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig()
.setTokenUrl("TokenUrl") .setTokenUrl("TokenUrl")
.setResponseType(Oauth2ResponseType.token) .setResponseType(Oauth2ResponseType.TOKEN)
.setClientSecret("ClientSecret") .setClientSecret("ClientSecret")
.setClientId("ClientId") .setClientId("ClientId")
.setAuthorizationUrl("AuthorizationUrl") .setAuthorizationUrl("AuthorizationUrl")
@ -329,7 +332,7 @@ public class Oauth2UtilTest {
public void checkOauthConfigCodeOrTokenResponseType() { public void checkOauthConfigCodeOrTokenResponseType() {
Oauth2Util.checkOauthConfig(new OAuthConfig() Oauth2Util.checkOauthConfig(new OAuthConfig()
.setTokenUrl("TokenUrl") .setTokenUrl("TokenUrl")
.setResponseType(Oauth2ResponseType.token) .setResponseType(Oauth2ResponseType.TOKEN)
.setClientSecret("ClientSecret") .setClientSecret("ClientSecret")
.setClientId("ClientId") .setClientId("ClientId")
.setAuthorizationUrl("AuthorizationUrl") .setAuthorizationUrl("AuthorizationUrl")
@ -340,43 +343,43 @@ public class Oauth2UtilTest {
public void checkOauthConfigClientCredentialsGrantType() { public void checkOauthConfigClientCredentialsGrantType() {
Oauth2Util.checkOauthConfig(new OAuthConfig() Oauth2Util.checkOauthConfig(new OAuthConfig()
.setTokenUrl("TokenUrl") .setTokenUrl("TokenUrl")
.setGrantType(Oauth2GrantType.client_credentials)); .setGrantType(Oauth2GrantType.CLIENT_CREDENTIALS));
} }
@Test @Test
public void checkOauthConfigPasswordGrantTypeAndNullUsernameAndPassword() { public void checkOauthConfigPasswordGrantTypeAndNullUsernameAndPassword() {
Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig() Assert.assertThrows(JapOauth2Exception.class, () -> Oauth2Util.checkOauthConfig(new OAuthConfig()
.setTokenUrl("TokenUrl") .setTokenUrl("TokenUrl")
.setGrantType(Oauth2GrantType.password))); .setGrantType(Oauth2GrantType.PASSWORD)));
} }
@Test @Test
public void checkOauthConfigPasswordGrantTypeAndHasUsernameAndPassword() { public void checkOauthConfigPasswordGrantTypeAndHasUsernameAndPassword() {
Oauth2Util.checkOauthConfig(new OAuthConfig() Oauth2Util.checkOauthConfig(new OAuthConfig()
.setTokenUrl("TokenUrl") .setTokenUrl("TokenUrl")
.setGrantType(Oauth2GrantType.password) .setGrantType(Oauth2GrantType.PASSWORD)
.setUsername("username") .setUsername("username")
.setPassword("password")); .setPassword("password"));
} }
@Test @Test
public void isCallbackCodeResponseType() { public void isCallbackCodeResponseType() {
boolean res = Oauth2Util.isCallback(httpServletRequestMock, new OAuthConfig() boolean res = Oauth2Util.isCallback(request, new OAuthConfig()
.setResponseType(Oauth2ResponseType.code)); .setResponseType(Oauth2ResponseType.CODE));
Assert.assertFalse(res); Assert.assertFalse(res);
} }
@Test @Test
public void isCallbackTokenResponseType() { public void isCallbackTokenResponseType() {
boolean res = Oauth2Util.isCallback(httpServletRequestMock, new OAuthConfig() boolean res = Oauth2Util.isCallback(request, new OAuthConfig()
.setResponseType(Oauth2ResponseType.token)); .setResponseType(Oauth2ResponseType.TOKEN));
Assert.assertFalse(res); Assert.assertFalse(res);
} }
@Test @Test
public void isCallbackNoneResponseType() { public void isCallbackNoneResponseType() {
boolean res = Oauth2Util.isCallback(httpServletRequestMock, new OAuthConfig() boolean res = Oauth2Util.isCallback(request, new OAuthConfig()
.setResponseType(Oauth2ResponseType.none)); .setResponseType(Oauth2ResponseType.NONE));
Assert.assertFalse(res); Assert.assertFalse(res);
} }
} }

View File

@ -20,6 +20,9 @@ import com.fujieid.jap.core.cache.JapLocalCache;
import com.fujieid.jap.core.context.JapAuthentication; import com.fujieid.jap.core.context.JapAuthentication;
import com.fujieid.jap.core.context.JapContext; import com.fujieid.jap.core.context.JapContext;
import com.fujieid.jap.core.exception.JapOauth2Exception; 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.OAuthConfig;
import com.fujieid.jap.oauth2.Oauth2GrantType; import com.fujieid.jap.oauth2.Oauth2GrantType;
import com.fujieid.jap.oauth2.Oauth2ResponseType; import com.fujieid.jap.oauth2.Oauth2ResponseType;
@ -40,45 +43,47 @@ import javax.servlet.http.HttpServletRequest;
*/ */
public class AccessTokenHelperTest { public class AccessTokenHelperTest {
public JapHttpRequest request;
@Mock @Mock
private HttpServletRequest httpServletRequestMock; private HttpServletRequest httpServletRequestMock;
@Before @Before
public void init() { public void init() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
this.request = new JakartaRequestAdapter(httpServletRequestMock);
} }
@Test @Test
public void getTokenNullOAuthConfig() { public void getTokenNullOAuthConfig() {
Assert.assertThrows(JapOauth2Exception.class, () -> AccessTokenHelper.getToken(httpServletRequestMock, null)); Assert.assertThrows(JapOauth2Exception.class, () -> AccessTokenHelper.getToken(request, null));
} }
@Test @Test
public void getTokenEmptyOAuthConfig() { public void getTokenEmptyOAuthConfig() {
Assert.assertThrows(JapOauth2Exception.class, () -> AccessTokenHelper.getToken(httpServletRequestMock, new OAuthConfig())); Assert.assertThrows(JapOauth2Exception.class, () -> AccessTokenHelper.getToken(request, new OAuthConfig()));
} }
@Test @Test
public void getTokenCodeResponseType() { public void getTokenCodeResponseType() {
Assert.assertThrows(JapOauth2Exception.class, () -> AccessTokenHelper.getToken(httpServletRequestMock, new OAuthConfig() Assert.assertThrows(JapOauth2Exception.class, () -> AccessTokenHelper.getToken(request, new OAuthConfig()
.setResponseType(Oauth2ResponseType.code))); .setResponseType(Oauth2ResponseType.CODE)));
} }
@Test @Test
public void getTokenCodeResponseTypeDoNotCheckState() { public void getTokenCodeResponseTypeDoNotCheckState() {
// Http url must be not blank! // 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) .setVerifyState(false)
.setResponseType(Oauth2ResponseType.code))); .setResponseType(Oauth2ResponseType.CODE)));
} }
@Test @Test
public void getTokenCodeResponseTypeNullCache() { public void getTokenCodeResponseTypeNullCache() {
JapAuthentication.setContext(new JapContext()); JapAuthentication.setContext(new JapContext());
JapAuthentication.getContext().setCache(null); JapAuthentication.getContext().setCache(null);
Assert.assertThrows(NullPointerException.class, () -> AccessTokenHelper.getToken(httpServletRequestMock, new OAuthConfig() Assert.assertThrows(NullPointerException.class, () -> AccessTokenHelper.getToken(request, new OAuthConfig()
.setVerifyState(false) .setVerifyState(false)
.setResponseType(Oauth2ResponseType.code) .setResponseType(Oauth2ResponseType.CODE)
.setEnablePkce(true) .setEnablePkce(true)
.setCallbackUrl("setCallbackUrl") .setCallbackUrl("setCallbackUrl")
.setTokenUrl("setTokenUrl"))); .setTokenUrl("setTokenUrl")));
@ -89,9 +94,9 @@ public class AccessTokenHelperTest {
// UnknownHostException: setTokenUrl // UnknownHostException: setTokenUrl
JapAuthentication.setContext(new JapContext()); JapAuthentication.setContext(new JapContext());
JapAuthentication.getContext().setCache(new JapLocalCache()); 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) .setVerifyState(false)
.setResponseType(Oauth2ResponseType.code) .setResponseType(Oauth2ResponseType.CODE)
.setEnablePkce(true) .setEnablePkce(true)
.setCallbackUrl("setCallbackUrl") .setCallbackUrl("setCallbackUrl")
.setTokenUrl("setTokenUrl"))); .setTokenUrl("setTokenUrl")));
@ -100,23 +105,23 @@ public class AccessTokenHelperTest {
@Test @Test
public void getTokenTokenResponseType() { public void getTokenTokenResponseType() {
// Oauth2Strategy failed to get AccessToken. // Oauth2Strategy failed to get AccessToken.
Assert.assertThrows(JapOauth2Exception.class, () -> AccessTokenHelper.getToken(httpServletRequestMock, new OAuthConfig() Assert.assertThrows(JapOauth2Exception.class, () -> AccessTokenHelper.getToken(request, new OAuthConfig()
.setResponseType(Oauth2ResponseType.token))); .setResponseType(Oauth2ResponseType.TOKEN)));
} }
@Test @Test
public void getTokenPasswordGrantTypeNullTokenUrl() { public void getTokenPasswordGrantTypeNullTokenUrl() {
// Http url must be not blank! // Http url must be not blank!
Assert.assertThrows(IllegalArgumentException.class, () -> AccessTokenHelper.getToken(httpServletRequestMock, new OAuthConfig() Assert.assertThrows(IllegalArgumentException.class, () -> AccessTokenHelper.getToken(request, new OAuthConfig()
.setGrantType(Oauth2GrantType.password) .setGrantType(Oauth2GrantType.PASSWORD)
.setScopes(new String[]{"read"}))); .setScopes(new String[]{"read"})));
} }
@Test @Test
public void getTokenPasswordGrantTypeErrorTokenUrl() { public void getTokenPasswordGrantTypeErrorTokenUrl() {
// UnknownHostException: setTokenUrl // UnknownHostException: setTokenUrl
Assert.assertThrows(IORuntimeException.class, () -> AccessTokenHelper.getToken(httpServletRequestMock, new OAuthConfig() Assert.assertThrows(JapOauth2Exception.class, () -> AccessTokenHelper.getToken(request, new OAuthConfig()
.setGrantType(Oauth2GrantType.password) .setGrantType(Oauth2GrantType.PASSWORD)
.setScopes(new String[]{"read"}) .setScopes(new String[]{"read"})
.setTokenUrl("setTokenUrl"))); .setTokenUrl("setTokenUrl")));
} }
@ -124,8 +129,8 @@ public class AccessTokenHelperTest {
@Test @Test
public void getTokenClientCredentialsGrantTypeErrorTokenUrl() { public void getTokenClientCredentialsGrantTypeErrorTokenUrl() {
// UnknownHostException: setTokenUrl // UnknownHostException: setTokenUrl
Assert.assertThrows(JapOauth2Exception.class, () -> AccessTokenHelper.getToken(httpServletRequestMock, new OAuthConfig() Assert.assertThrows(JapOauth2Exception.class, () -> AccessTokenHelper.getToken(request, new OAuthConfig()
.setGrantType(Oauth2GrantType.client_credentials) .setGrantType(Oauth2GrantType.CLIENT_CREDENTIALS)
.setScopes(new String[]{"read"}) .setScopes(new String[]{"read"})
.setTokenUrl("setTokenUrl"))); .setTokenUrl("setTokenUrl")));
} }

View File

@ -25,12 +25,11 @@ import com.fujieid.jap.core.exception.JapException;
import com.fujieid.jap.core.exception.OidcException; import com.fujieid.jap.core.exception.OidcException;
import com.fujieid.jap.core.result.JapErrorCode; import com.fujieid.jap.core.result.JapErrorCode;
import com.fujieid.jap.core.result.JapResponse; 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.OAuthConfig;
import com.fujieid.jap.oauth2.Oauth2Strategy; 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. * 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, * 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 * @param response The response to authenticate
*/ */
@Override @Override
public JapResponse authenticate(AuthenticateConfig config, HttpServletRequest request, HttpServletResponse response) { public JapResponse authenticate(AuthenticateConfig config, JapHttpRequest request, JapHttpResponse response) {
try { try {
this.checkAuthenticateConfig(config, OidcConfig.class); this.checkAuthenticateConfig(config, OidcConfig.class);

View File

@ -19,6 +19,7 @@ import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.fujieid.jap.core.exception.OidcException; import com.fujieid.jap.core.exception.OidcException;
import com.xkcoding.http.HttpUtil; import com.xkcoding.http.HttpUtil;
import com.xkcoding.http.support.SimpleHttpResponse;
import com.xkcoding.json.JsonUtil; import com.xkcoding.json.JsonUtil;
import com.xkcoding.json.util.Kv; import com.xkcoding.json.util.Kv;
@ -43,13 +44,12 @@ public class OidcUtil {
} }
String discoveryUrl = issuer.concat(DISCOVERY_URL); String discoveryUrl = issuer.concat(DISCOVERY_URL);
String response = null; SimpleHttpResponse response = HttpUtil.get(discoveryUrl);
try { if(!response.isSuccess()) {
response = HttpUtil.get(discoveryUrl); throw new OidcException("Cannot access discovery url: " + discoveryUrl + ", " + response.getError());
} catch (Exception e) {
throw new OidcException("Cannot access discovery url: " + discoveryUrl);
} }
Kv oidcDiscoveryInfo = JsonUtil.parseKv(response);
Kv oidcDiscoveryInfo = JsonUtil.parseKv(response.getBody());
if (CollectionUtil.isEmpty(oidcDiscoveryInfo)) { if (CollectionUtil.isEmpty(oidcDiscoveryInfo)) {
throw new OidcException("Unable to parse IDP service discovery configuration information."); throw new OidcException("Unable to parse IDP service discovery configuration information.");
} }

View File

@ -15,10 +15,10 @@
*/ */
package com.fujieid.jap.simple; 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; import java.io.Serializable;
/** /**
@ -38,13 +38,13 @@ public class JapAuthenticationDetails implements Serializable {
private final String sessionId; private final String sessionId;
public JapAuthenticationDetails(HttpServletRequest request) { public JapAuthenticationDetails(JapHttpRequest request) {
this.clientIp = RequestUtil.getIp(request); this.clientIp = RequestUtil.getIp(request);
this.remoteAddress = request.getRemoteAddr(); 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; this.sessionId = (session != null) ? session.getId() : null;
} }

Some files were not shown because too many files have changed in this diff Show More