草庐IT

spring - Spring oauth2 token 请求中未实际使用的基本身份验证过滤器和身份验证入口点

coder 2023-05-11 原文

我已经基于 spring 的 sparklr 示例应用程序和我在网上找到的几个示例,使用 spring oauth2 实现了资源所有者流程。我像这样用 curl 测试了 token 请求部分,以提供客户端和用户凭据:

curl -v --data "username=user1&password=user1&client_id=client1&client_secret=client1&grant_type=password" -X POST "http://localhost:8080/samplerestspringoauth2/oauth/token"

它工作正常,但是我做了以下观察:

虽然根据我看到的例子,我使用了BasicAuthentication过滤器,但在安全过程中并没有真正使用它。由于 token 请求不包含 Authentication header ,因此 BasicAuthentication 过滤器只会跳过任何检查。 ClientCredentialsTokenEndpointFilter 和 authentication-server 是唯一在 token 请求期间执行安全检查的。在注意到这一点并通过调试进行验证后,我尝试完全删除以下部分:

<http-basic entry-point-ref="clientAuthenticationEntryPoint" />



从配置。但后来我收到警告:

"No AuthenticationEntryPoint could be established. Please make sure you have a login mechanism configured through the namespace (such as form-login) or specify a custom AuthenticationEntryPoint with the 'entry-point-ref' attribute".



下一步,我在http命名空间中添加了entry-point-ref="clientAuthenticationEntryPoint,并摆脱了警告。我测试了应用程序并正确播放。

但是,除了上述之外,我在调试过程中还进行了以下观察:
ClientCredentialsTokenEndpointFilter 在私有(private)变量中包含自己的 OAuth2AuthenticationEntryPoint 入口点,并在由于客户端凭据错误而失败时使用该入口点。
因此,我在基本过滤器或 http 命名空间中指定哪个入口点并不重要。最后 ClientCredentialsTokenEndpointFilter 将使用它自己的私有(private) OAuth2AuthenticationEntryPoint。
总结一下我的结论似乎如下:
  • 基本过滤器不使用,可以删除,如果我们指定
    取而代之的是 http 命名空间中的端点。
  • 指定一个基本的
    过滤器,或者只有 http 命名空间中的端点才需要
    编译器停止警告。它们没有实际用途,而且
    使用的端点在内部硬编码
    ClientCredentialsTokenEndpointFilter。

  • 下面我把token请求的http和endpoint配置放出来供大家引用。我跳过其余的配置以保持帖子易于阅读:
    <http pattern="/oauth/token" create-session="stateless"
            authentication-manager-ref="clientAuthenticationManager"
            xmlns="http://www.springframework.org/schema/security">
            <intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />
            <anonymous enabled="false" />
            <http-basic entry-point-ref="clientAuthenticationEntryPoint" />
            <custom-filter ref="clientCredentialsTokenEndpointFilter"
                before="BASIC_AUTH_FILTER" />
            <access-denied-handler ref="oauthAccessDeniedHandler" />
        </http>
    
    <bean id="clientAuthenticationEntryPoint"
            class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
            <property name="realmName" value="springsec/client" />
            <property name="typeName" value="Basic" />
        </bean>
    

    我还假设在原始 sparklr 应用程序(它是 spring oauth2 示例应用程序)的 token 请求配置中也发生了同样的问题,这是非常相似的。可以在 https://github.com/spring-projects/spring-security-oauth/blob/master/samples/oauth2/sparklr/src/main/webapp/WEB-INF/spring-servlet.xml 中找到,相关部分如下:
    <http pattern="/oauth/token" create-session="stateless"
                    authentication-manager-ref="clientAuthenticationManager"
                    xmlns="http://www.springframework.org/schema/security">
                    <intercept-url pattern="/**" method="GET" access="ROLE_DENY" />
                    <intercept-url pattern="/**" method="PUT" access="ROLE_DENY" />
                    <intercept-url pattern="/**" method="DELETE" access="ROLE_DENY" />
                    <intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
                    <anonymous enabled="false" />
                    <http-basic entry-point-ref="clientAuthenticationEntryPoint" />
                    <!-- include this only if you need to authenticate clients via request
                            parameters -->
                    <custom-filter ref="clientCredentialsTokenEndpointFilter"
                            after="BASIC_AUTH_FILTER" />
                    <access-denied-handler ref="oauthAccessDeniedHandler" />
            </http>
    

    我希望 spring oauth2 能够更恰本地与 spring 安全交互,而不必放置不必要的和误导性的配置,这让我觉得我可能错过了一些东西。由于安全性是一个敏感的方面,我想与您分享并询问我的结论是否正确。

    最佳答案

    /oauth/token 提供了两种不同的方式来验证请求 token 的客户端:

  • 使用 HTTP-Basic 身份验证(当存在“http-basic”元素时)

    身份验证由 org.springframework.security.web.authentication.www.BasicAuthenticationFilter 处理,并处理包含客户端 base64 编码凭据的“授权”HTTP header 。过滤器仅在 Authorization header 存在时执行处理。这种方法总是首先尝试。 http-basic 上定义的入口点只会在用户提供包含无效内容的“授权” header 时调用 - 这就是为什么您在调试器中看不到调用的入口点,请尝试设置授权 HTTP header 和断点会受到打击。
  • 如 OAuth 标准中定义的那样,使用 client_id 和 client_secret HTTP 参数

    这是使用 org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter 处理的,默认情况下使用将 WWW-Authenticate header 发送回客户端的入口点。可以自定义默认入口点(有一个 setAuthenticationEntryPoint 方法)。入口点仅在您提供 client_id 参数时使用。

  • 这两种方法使用不同的方式来获取客户端的用户名+密码,但使用相同的身份验证管理器进行验证。

    您在取出 元素时观察到的“无法建立 AuthenticationEntryPoint”错误来自 Spring Security 本身,而不是来自 OAuth 扩展。原因是 Spring Security 无法判断在自定义过滤器 ClientCredentialsTokenEndpointFilter 中已经配置了一个默认入口点。并且 Spring Security 的 HTTP 配置始终必须至少有一个可用的入口点。

    所以,完整的逻辑如下:
  • 当您包含具有无效凭据的“授权” header 并且存在 元素时,系统将使用在 元素上定义的入口点。如果未指定(缺少属性 entry-point-ref),系统将自动为您创建 BasicAuthenticationEntryPoint 的默认实例并使用它。
  • 当您包含具有无效凭据的 HTTP 参数“client_id”和“client_secret”并且存在自定义过滤器 clientCredentialsTokenEndpointFilter 时,系统将使用在 clientCredentialsTokenEndpointFilter bean(默认情况下是 OAuth2AuthenticationEntryPoint 的实例)中定义的入口点
  • 如果“Authorization” header 和“client_id”参数都不存在并且端点需要身份验证(“IS_AUTHENTICATED_FULLY”),系统将使用 上定义的入口点,如果存在,否则它将使用 http-basic 上定义的入口点(如上)
  • 如果您既没有指定 http-basic(或 Spring 识别的其他默认身份验证方法),也没有使用 指定默认入口点,系统将失败并显示“无法建立 AuthenticationEntryPoint ",因为它至少需要一个入口点,并且它不知道在 clientCredentialsTokenEndpointFilter 中有一个可用的入口点。

  • 关于你的观察:

    >> The basic filter is not used and can be removed, if we specify the endpoint in the http namespace instead.



    > 如果您使用 client_id + client_secret 对您的客户进行身份验证,这是正确的

    >> Specifying either a basic filter,or an endpoint in http namespace is needed only for the compiler to stop the warning. They have no practical use, and the endpoint used is hardcoded inside ClientCredentialsTokenEndpointFilter.



    > 部分正确,因为如果缺少 client_id,将使用入口点。

    配置确实令人困惑(部分原因是 OAuth 不是 Spring Security 的 native 部分,而是扩展),但所有这些设置都有意义并且在特定情况下使用。

    您所做的更改没有安全隐患。

    关于spring - Spring oauth2 token 请求中未实际使用的基本身份验证过滤器和身份验证入口点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21451245/

    有关spring - Spring oauth2 token 请求中未实际使用的基本身份验证过滤器和身份验证入口点的更多相关文章

    1. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

      给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

    2. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

      我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

    3. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

      我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

    4. ruby-on-rails - 如何验证非模型(甚至非对象)字段 - 2

      我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss

    5. ruby-on-rails - 如何将验证与模型分开 - 2

      我有一些非常大的模型,我必须将它们迁移到最新版本的Rails。这些模型有相当多的验证(User有大约50个验证)。是否可以将所有这些验证移动到另一个文件中?说app/models/validations/user_validations.rb。如果可以,有人可以提供示例吗? 最佳答案 您可以为此使用关注点:#app/models/validations/user_validations.rbrequire'active_support/concern'moduleUserValidationsextendActiveSupport:

    6. ruby-on-rails - 跳过状态机方法的所有验证 - 2

      当我的预订模型通过rake任务在状态机上转换时,我试图找出如何跳过对ActiveRecord对象的特定实例的验证。我想在reservation.close时跳过所有验证!叫做。希望调用reservation.close!(:validate=>false)之类的东西。仅供引用,我们正在使用https://github.com/pluginaweek/state_machine用于状态机。这是我的预订模型的示例。classReservation["requested","negotiating","approved"])}state_machine:initial=>'requested

    7. ruby - 如何在 Rails 4 中使用表单对象之前的验证回调? - 2

      我有一个服务模型/表及其注册表。在表单中,我几乎拥有服务的所有字段,但我想在验证服务对象之前自动设置其中一些值。示例:--服务Controller#创建Action:defcreate@service=Service.new@service_form=ServiceFormObject.new(@service)@service_form.validate(params[:service_form_object])and@service_form.saverespond_with(@service_form,location:admin_services_path)end在验证@ser

    8. ruby - 如何验证 IO.copy_stream 是否成功 - 2

      这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

    9. ruby-on-rails - 事件管理员日期过滤器日期格式自定义 - 2

      是否有简单的方法来更改默认ISO格式(yyyy-mm-dd)的ActiveAdmin日期过滤器显示格式? 最佳答案 您可以像这样为日期选择器提供额外的选项,而不是覆盖js:=f.input:my_date,as::datepicker,datepicker_options:{dateFormat:"mm/dd/yy"} 关于ruby-on-rails-事件管理员日期过滤器日期格式自定义,我们在StackOverflow上找到一个类似的问题: https://s

    10. ruby-on-rails - 在 Controller 中干净地处理多个过滤器(参数) - 2

      我有一个名为Post的类,我需要能够适应以下场景:如果用户选择了一个类别,则只显示该类别的帖子如果用户选择了一种类型,则只显示该类型的帖子如果用户选择了一个类别和类型,则只显示该类别中该类型的帖子如果用户没有选择任何内容,则显示所有帖子我想知道我的Controller是否不可避免地会因大量条件语句而显得粗糙...这是我解决此问题的错误方法-有谁知道我如何才能做到这一点?classPostsController 最佳答案 您最好遵循“胖模型,瘦Controller”的惯例,这意味着您应该将这种逻辑放在模型本身中。Post类应该能够报告

    随机推荐