编写Java库构建OAuth 2.0授权服务器 / OpenID连接身份提供商
#java #oauth2 #openidconnect #oidc

AZIDP4J

我正在写AzIdP4J,该库是在Java中构建授权服务器和身份提供商的库。
这篇文章讨论了我在开发时的想法。

inabajunmr/azidp4j: Library for Java OAuth 2.0 Authorization Server & OpenID Connect Identity Provider

库作为以下示例的工作。

// Convert HTTP Request query parameters to Map
var authorizationRequestQueryParameterMap =
        Map.of(
                "scope", "openid item:read",
                "response_type", "code",
                "client_id", "xyz-client",
                "redirect_uri", "https://client.example.com/callback",
                "state", "abc",
                "nonce", "xyz");
var authorizationRequest =
        new AuthorizationRequest(
                "inabajun", // authenticated user subject. Application needs to implements user authentication. If no user is authenticated, specify null.
                Instant.now().getEpochSecond(),
                Set.of("openid", "item:read"), // User consented scopes. Application needs to implements user consent.
                authorizationRequestQueryParameterMap);

// Authorization Request
var response = azIdP.authorize(authzReq);

// Library returns what should do next so implements application's behavior.
switch (response.next) {
    case redirect -> {
        // Redirect to response.redirect.redirectTo
    }
    case additionalPage -> {
        // Implements additional process like login or consent or...
    }
    case errorPage -> {
        // Error happend but can't redirect to redirct_uri
    }
}

当您想要授权服务器 /身份提供商时

当我们想要授权服务器 /身份提供商时,我们可以选择以下模式。< / p>

  • 自己开发它们
  • 用库开发它们
  • 使用与您的应用程序一起用作授权服务器 /身份提供商的服务< / li>
  • 使用独立授权服务器 /身份提供商< / li>

在刮擦开发的情况下,我们需要编写许多来源。我们需要了解规格。我们需要继续学习新的规格和趋势...

我经常觉得自己开发用户体验,但是将有关OAUTH 2.0 / OIDC(OIDC)的协议的流程委派给了库。因此,我正在开发库来构建Java中的OAuth 2.0授权服务器 / OIDC身份提供商。 (因为Spring Security Oauth已经是EOL。)

政策

我认为库最重要的是界面。
我决定采用以下政策考虑接口。

  • 不依赖特定框架
  • 易于发出访问令牌 / ID令牌< / li>
  • 应用程序可以自己实施用户体验
  • 没有数据存储实现

不要依赖特定框架

oauth 2.0 / OpenID连接取决于HTTP作为规范。因此,如果可以在没有任何其他实现的情况下使用库,则库需要直接接受HTTP请求。

但是有许多Java Web应用程序框架,我想实现一个可用于任何框架的库。

因此,Azidp4J比直接接受HTTP请求更抽象的接口。

例如,令牌请求 /令牌响应表示为以下示例。< / p>

Spring based example implementation就是这样。

@PostMapping(value = "token", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public ResponseEntity<Map> tokenEndpoint(@RequestParam MultiValueMap<String, Object> body) {

    // client authentication by the application...
    // convert HTTP request query parameters to Map
    var request = new TokenRequest(authenticatedClientId, body.toSingleValueMap();
    // Token Request
    var response =
            azIdP.issueToken(request);

    // convert AzIdP4J resposne to HTTP response
    return ResponseEntity.status(response.status).body(response.body);
}

另一方面,AzIDP4J不支持高度依赖框架的协议中的功能。例如,我认为许多框架具有对客户端进行身份验证并由Bearer令牌授权的功能,因此Azidp4j不支持它们。

易于发行的访问令牌 / ID令牌

我决定通过授权代码流轻松实施发出每个令牌。如果支持许多功能使接口变得复杂,则AZIDP4J不支持它们。

例如,如果AzIDP4J支持UserInfo端点,则Azidp4J需要了解用户,但它使接口变得复杂,因此我不支持它。

应用程序可以自己实施用户体验

授权请求后的行为在协议中没有关闭。当授权请求有及时=登录时,该应用程序需要显示登录页面,但是如何提供身份验证的用户体验不在这些规范的范围之内。该应用程序需要提供特定于应用程序的身份验证流。 AZIDP4J希望不影响用户身份验证,同意等等用户体验...

SO AZIDP4J提供以下接口。

// authzReq has authenticated user subject but can expresses not authenticated.
var response = azIdP.authorize(authzReq);
// Library returns what should do next so implements application's behavior.
switch (response.next) {
    case redirect -> {
        // Redirect to response.redirect.redirectTo
    }
    case additionalPage -> {
        // Implements additional process like login or consent or...
    }
    case errorPage -> {
        // Error happend but can't redirect to redirct_uri
    }

Authorization Request Document

没有数据存储实现

我喜欢ory/fosite接口,因此Azidp4j模仿它们。 Azidp4j需要管理令牌,因此仅提供接口,并且应用程序需要实现它们。

不支持的事情

当我实施协议时,我将希望实施任何规格,但我决定不支持控制我的动机的事情。

我决定了第一个里程碑。

  • 使Azidp4J至少起作用
  • 用具体示例编写文档

对于这一里程碑,我在第一个里程碑上删除了以下内容。

  • 不支持所有核心规范
    • 例如,请求对象
    • 不支持我不理解具体需求的规格。

很难支持哪些规格。

至少使Azidp4J起作用

首先,我实施了接受授权请求,并通过令牌端点发布了访问令牌和ID令牌。我经常在实施时测试OICD Conformance Test反对我的实施。这使得进步可见,因此继续我的动力是很好的。一致性测试揭示了一些我也无法正确理解的规范。

用具体示例编写文档

我通过一致性测试,写作来源等了解了一些规格。但是我不明白库的界面是好还是坏。我想要有关图书馆的反馈,因此我编写了带有具体示例的文档。如果您提供反馈,我会很高兴。

AzIdP4J Documentation

发展过程

为了连续检查策略“不依赖特定框架”,我实施了2种示例身份框架。

这种方法有助于我对接口的决定。例如,当我考虑使用库的应用程序是否可以实现客户端身份验证时,多个实现有助于我的考虑。

具有客户实现的图书馆开发不仅仅是测试用例更好。我从后者中找不到的情况有时会出现。

结论

我正在写AzIdP4J,该库是在Java中构建授权服务器和身份提供商的库。
这篇文章谈到了我在开发时的想法。

inabajunmr/azidp4j: Library for Java OAuth 2.0 Authorization Server & OpenID Connect Identity Provider

库作为以下示例的工作。

// convert HTTP Request query parameters to Map
var authorizationRequestQueryParameterMap =
        Map.of(
                "scope", "openid item:read",
                "response_type", "code",
                "client_id", "xyz-client",
                "redirect_uri", "https://client.example.com/callback",
                "state", "abc",
                "nonce", "xyz");
var authorizationRequest =
        new AuthorizationRequest(
                "inabajun", // authenticated user subject. Application needs to implements user authentication. If no user is authenticated, specify null.
                Instant.now().getEpochSecond(),
                Set.of("openid", "item:read"), // User consented scopes. Application needs to implements user consent.
                authorizationRequestQueryParameterMap);
var response = azIdP.authorize(authzReq);
// Library returns what should do next so implements application's behavior.
switch (response.next) {
    case redirect -> {
        // Redirect to response.redirect.redirectTo
    }
    case additionalPage -> {
        // Implements additional process like login or consent or...
    }
    case errorPage -> {
        // Error happend but can't redirect to redirct_uri
    }
}

我希望您的反馈。谢谢。