java servlet3.1规范解读系列六:安全模块

规范中提供的安全处理,在我的理解中只是提供了一种安全控制的思路,并不是真实可用的

所以在这里就仅仅介绍下规范中安全的相关定义,然后在结合spring Security 说下web安全认证的整个处理

 

安全

应用开发人员创建 Web 应用,他给、销售或其他方式转入应用给部署人员,部署人员覆盖安装到运行时环境。应用开发人员与部署人员沟通部署系统的安全需求。该信息可以通过应用部署描述符声明传达,通过在应用代码中使用注解, 或通过 ServletRegistration 接口的 setServletSecurity 方法编程。本节描述了 Servlet 容器安全机制、接口、部署描述符和基于注解机制和编程机制用于传达应用安全需求。

13.1 介绍

web 应用包含的资源可以被多个用户访问。这些资源常常不受保护的遍历,开放网络如 Internet。在这样的环境,大量的 web 应用将有安全需求。

尽管质量保障和实现细节可能会有所不同,但 servlet 容器有满足这些需求的机制和基础设施,共用如下一些特性:

■ 身份认证: 表示通信实体彼此证明他们具体身份的行为是被授权访问的。

■ 资源访问控制: 表示和资源的交互是受限于集合的用户或为了强制完整性、保密性、或可用性约束的程序。

■ 数据完整性: 表示用来证明信息在传输过程中没有被第三方修改。

■ 保密或数据隐私: 表示用来保证信息只对以授权访问的用户可用。

 

13.3 编程式安全

编程式安全包括以下 HttpServletRequest 接口的方法:

■ authenticate

■ login

■ logout

■ getRemoteUser

■ isUserInRole

■ getUserPrincipal

login 方法允许应用执行用户名和密码收集(作为一种 Form-Based Login 的替代)。

authenticate 方法允许应用由容器发起在一个不受约束的请求上下文内的来访者请求认证。

logout 方法提供用于应用重置来访者的请求身份。

getRemoteUser 方法由容器返回与该请求相关的远程用户(即来访者)的名字。

isUserInRole 方法确定是否与该请求相关的远程用户(即来访者)在一个特定的安全角色中。

getUserPrincipal 方 法 确 定 远 程 用 户 ( 即 来 访 者 ) 的 Principal 名 称 并 返 回 一 个 与 远 程 用 户 相 关 的java.security.Principal 对象。调用 getUserPrincipal 返回的 Principal 的 getName 方法返回远程用户的名字。这些 API 允许 Servlet 基于获得的信息做一些业务逻辑决策。

如果没有用户通过身份认证, getRemoteUser 方法返回 null, isUserInRole 方法总返回 false, getUserPrincipal方法总返回 null。

isUserInRole 方法需要一个引用应用角色的参数。对于用在调用 isUserInRole 的每一个单独的角色引用,一个 带 有 关 联 到 角 色 引 用 的 role-name 的 security-role-ref 元 素 应 该 声 明 在 部 署 描 述 符 中 。 每 一 个security-role-ref 元素应该包含一个 role-link 子元素,其值是应用内嵌的角色引用链接到的应用安全角色名称。容器使用 security-role-ref 的 role-name 是否等于角色引用来决定哪一个 security-role 用于测试用户是否在身份中。

例如,映射安全角色应用“ FOO”到 role-name 为"manager"的安全角色的语法是:

<security-role-ref>

<role-name>FOO</role-name>

<role-link>manager</role-link>

</security-role-ref>

在这种情况下, 如果属于“ manager”安全角色的用户调用了 servlet,则调用 isUserInRole("FOO") API 的结果是 true。

如果用于调用 isUserInRole 的一个角色引用,没有匹配的 security-role-ref 存在 , 容 器 必 须 默 认 以security-role 的 role-name 等于用于调用的角色引用来测试用户身份。

角色名“ *”应该从不用作调用 isUserInRole 的参数。任何以“ *”调用 isUserInRole 必须返回 false。如果security-role 的 role-name 使用“ **”测试,且应用没有声明一个 role-name 为“ **”的应用 security-role,isUserInRole 必须仅返回 true。

如果用户已经认证;即,仅当 getRemoteUser 和 getUserPrincipal 将同时返回非 null 值。否则,容器必须检查用户身份是否在应用角色中。

security-role-ref 元素声明通知部署人员应用使用的角色引用和必须定义哪一个映射。

 

总结: 不管是模拟登陆login和角色判断,这些都是比较死板的,基本没什么用处

 

 

编程式安全策略配置

本章定义的注解和 API 提供用于配置 Servlet 容器强制的安全约束。

13.4.1 @ServletSecurity 注解

@ServletSecurity 提供了用于定义访问控制约束的另一种机制,相当于那些通过在便携式部署描述符中声明式或通过 ServletRegistration 接口的 setServletSecurity 方法编程式表示。 Servlet 容器必须支持在实现javax.servlet.Servlet 接口的类(和它的子类)上使用@ServletSecurity 注解。

package javax.servlet.annotation;

@Inherited

@Documented

@Target(value=TYPE)

@Retention(value=RUNTIME)

public @interface ServletSecurity {

HttpConstraint value();

HttpMethodConstraint[] httpMethodConstraints();

}

表 13-1 ServletSecurity 接口

元素

描述

默认值

value

HttpConstraint 定义了应用到没有在 httpMethodConstraints

返回的数组中表示的所有 HTTP 方法的保护。

@HttpConstraint

httpMethodConstraints

HTTP 方法的特定限制数组

{}

@HttpConstraint

@HttpConstraint 注解用在@ServletSecurity 中表示应用到所有 HTTP 协议方法的安全约束,且 HTTP 协议方法对应的@HttpMethodConstraint 没有出现在@ServletSecurity 注解中。

对于一个@HttpConstraint 返回所有默认值发生在与至少一个@HttpMethodConstraint 返回不同于所有默认值的组合的特殊情况, @HttpMethodConstraint 表示没有安全约束被应用到任何 HTTP 协议方法,否则一个安全约束将应用。这个例外是确保这些潜在的非特定@HttpConstraint 使用没有产生约束,这将明确建立不受保护的访问这些方法;因为,它们没有被约束覆盖。

package javax.servlet.annotation;

@Documented

@Retention(value=RUNTIME)

public @interface HttpConstraint {

ServletSecurity.EmptyRoleSemantic value();

java.lang.String[] rolesAllowed();

ServletSecurity.TransportGuarantee transportGuarantee();

}

表 13-2 HttpConstraint 接口

元素

描述

默认值

value

当 rolesAllowed 返回一个空数组,(只)应用的默认授权语

义。

PERMIT

rolesAllowed

包含授权角色的数组

{}

transportGuarantee

在连接的请求到达时必须满足的数据保护需求。

NONE

@HttpMethodConstraint

@HttpMethodConstraint 注解用在@ServletSecurity 注解中表示在特定 HTTP 协议消息上的安全约束。

package javax.servlet.annotation;

@Documented

@Retention(value=RUNTIME)

public @interface HttpMethodConstraint {

ServletSecurity.EmptyRoleSemantic value();

java.lang.String[] rolesAllowed();

ServletSecurity.TransportGuarantee transportGuarantee();

}

表 13-3 HttpMethodConstraint 接口

元素

描述

默认值

   

value

HTTP 协议方法名

    

emptyRoleSemantic

当 rolesAllowed 返回一个空数组,(只)应用的默认授权

语义。

PERMIT

   

rolesAllowed

包含授权角色的数组

{}

   

transportGuarantee

在连接的请求到达时必须满足的数据保护需求。

NONE

   

@ServletSecurity 注解可以指定在(更准确地说,目标是) Servlet 实现类上,且根据@Inherited 元注解定义的规则,它的值是被子类继承的。至多只有一个@ServletSecurity 注解实例可以出现在 Servlet 实现类上,且@ServletSecurity 注解必须不指定在(更准确地说,目标是)Java 方法上。

当一个或多个@HttpMethodConstraint 注解定义在@ServletSecurity 注解中时,每一个@HttpMethodConstraint定 义 的 security-constraint , 其 应 用到 @HttpMethodConstraint 中 标 识 的 HTTP 协 议 方法 。 除了 它 的@HttpConstraint 返回所有默认值、和它包含至少一个返回不同于所有默认值的@HttpMethodConstraint 的情况 之 外 , @ServletSecurity 注 解 定 义 另 一 个 security-constraint 应 该 到 所 有 还 没 有 定 义 相关@HttpMethodConstraint 的 HTTP 协议方法。

定义在便携式部署描述符中的 security-constraint 元素用于对所有出现在该约束中的 url-pattern 授权。

当 在 便 携 式 部 署 描 述 符 中 的 一 个 security-constraint 包 含 一 个 url-pattern ,其 精 确 匹 配 一 个 使 用@ServletSecurity 注解的模式映射到的类,该注解必须在由容器在该模式上强制实施的约束上没有效果。当为便携式部署描述符定义了 metadata-complete=true 时, @ServletSecurity 注解不会应用到部署描述符中的任何 url-pattern 映射到(任何 servlet 映射到)的注解类。

@ServletSecurity 注解不应用到 ServletRegistration 使用 ServletContext 接口的 addServlet(String, Servlet)方法创建的 url-pattern,除非该 Servlet 是由 ServletContext 接口的 createServlet 方法构建的。除了上面列出的,当一个 Servlet 类注解了@ServletSecurity,该注解定义的安全约束应用到所有 url-pattern映射到的所有 Servlet 映射到的类。

当一个类没有加@ServletSecurity 注解时,应用到从那个类映射到的 Servlet 的访问策略是由合适的

security-constraint 元素确定的,如果有,在相关的便携式部署描述符,或者由约束禁止任何这样的标签,则如果有,为目标 servlet 通过 ServletRegistration 接口的 setServletSecurity 方法编程式确定的。

13.4.1.1 示例

以下示例演示了 ServletSecurity 注解的使用。

代码示例 13-1 用于所有 HTTP 方法,且无约束

@ServletSecurity

public class Example1 extends HttpServlet {

}

代码示例 13-2 用于所有 HTTP 方法,无认证约束,需要加密传输

@ServletSecurity(@HttpConstraint(transportGuarantee = TransportGuarantee.CONFIDENTIAL))

public class Example2 extends HttpServlet {

}

代码示例 13-3 用于所有 HTTP 方法,所有访问拒绝

@ServletSecurity(@HttpConstraint(EmptyRoleSemantic.DENY))

public class Example3 extends HttpServlet {

}

代码示例 13-4 用于所有 HTTP 方法,认证约束需要成员身份在角色“ R1”中

@ServletSecurity(@HttpConstraint(rolesAllowed = "R1"))

public class Example4 extends HttpServlet {

}

代码示例 13-5 用于除 GET 和 POST 之外的所有 HTTP 方法,无约束;对于 GET 和 POST 方法, 认证约束需要成员身份在角色“ R1”中;对于 POST,需要加密传输

@ServletSecurity((httpMethodConstraints = {

@HttpMethodConstraint(value = "GET", rolesAllowed = "R1"),

@HttpMethodConstraint(value = "POST", rolesAllowed = "R1",

transportGuarantee = TransportGuarantee.CONFIDENTIAL)

})

public class Example5 extends HttpServlet {

}

代码示例 13-6 用于除了 GET 之外的所有 HTTP 方法,认证约束需要成员身份在“ R1”角色中; 对于 GET,无约束

@ServletSecurity(value = @HttpConstraint(rolesAllowed = "R1"),

httpMethodConstraints = @HttpMethodConstraint("GET"))

public class Example6 extends HttpServlet {

}

代码示例 13-7 用于除了 TRACE 之外的所有 HTTP 方法,认证约束需要成员身份在“ R1”角色中;对于TRACE,拒绝所有访问

@ServletSecurity(value = @HttpConstraint(rolesAllowed = "R1"),

httpMethodConstraints = @HttpMethodConstraint(value="TRACE",

emptyRoleSemantic = EmptyRoleSemantic.DENY))

public class Example7 extends HttpServlet {

}

总结: 从上面这一段的描述中,主要是@ServletSecurity 的使用,作用是限制角色,限制请求方法,限制传输方式,比较能用的也就是对请求方法的限制了,其他并没有好的用途

13.4.1.2 映射@ServletSecurity 为 security-constraint

本节将介绍@ServletSecurity 注解映射为它等价表示, security-constraint 元素。这提供了使用已存在容器的security-constraint 实施机制来简化实施。由 Servlet 容器实施的@ServletSecurity 注解必须在实施的效果上是等价的,由容器从在本节中定义的映射产生 security-constraint 元素。

@ServletSecurity 注 解 用 于 定 义 一 个 方 法 无 关 的 @HttpConstraint , 且 紧 跟 着 一 个 包 含 零 个 或 多 个@HttpMethodConstraint 规格的列表。方法无关的约束应用到那些没有定义 HTTP 特定方法约束的所有 HTTP方法。

当没有包含@HttpMethodConstraint 元素, @ServletSecurity 注解相当于包含一个 web-resource-collection 的单个 security-constraint 元素,且 web-resource-collection 不包含 http-method 元素,因此涉及到所有 HTTP 方法。

下 面 的 例 子 展 示 了 把 一 个 不 包 含 @HttpMethodConstraint 注 解 的 @ServletSecurity 注 解 表 示 为 单 个security-constraint 元素。 相关的 servlet ( registration)定义的 url-pattern 元素将被包含在 web-resource-collection中, 任何包含的 auth-constraint 和 user-data-constraint 元素的存在和值,将由定义在 13-132 页中 13.4.1.3节的“映射@HttpConstraint 和 @HttpMethodConstraint 为 XML”的映射的@HttpConstraint 的值确定。

代码示例 13-8 不包含@HttpMethodConstraint 的映射@ServletSecurity

@ServletSecurity(@HttpConstraint(rolesAllowed = "Role1"))

<security-constraint>

<web-resource-collection>

<url-pattern>...</url-pattern>

</web-resource-collection>

<auth-constraint>

<role-name>Role1</role-name>

</auth-constraint>

</security-constraint>

当指定了一个或多个@HttpMethodConstraint 元素,方法无关的约束关联一个单个 security-constraint 元素,其 , web-resource-collection 包 含 了 为 每 一 个 HTTP 方 法 命 名 在 @HttpMethodConstraint 元 素 中 的http-method-omission 元素。如果方法无关的约束返回所有默认值和至少一个@HttpMethodConstraint 不是,包含 http-method-omission 元素的 security-constraint 必须不被创建。 每一个@HttpMethodConstraint 与另一种包含一个 web-resource-collection 的 security-constraint 关联, web-resource-collection 包含一个使用相应 HTTP

方法命名的 http-method 元素。下面的例子展示了映射带有单个@HttpMethodConstraint 的@ServletSecurity 注解为两种 security-constraint元素。相应的 Servlet ( registration) 定义的 url-pattern 元素将被包含在两种约束的 web-resource-collection 中,且任何包含的 auth-constraint 和 user-data-constraint 元素的存在和值,将由定义在 13-135 页中 13.4.1.3 节的

“ 映 射 @HttpConstraint 和 @HttpMethodConstraint 为 XML ” 的 映 射 关 联 的 @HttpConstraint 和

@HttpMethodConstraint 的值确定。

代码示例 13-9 映射包含@HttpMethodConstraint 的@ServletSecurity

@ServletSecurity(value=@HttpConstraint(rolesAllowed = "Role1"),

httpMethodConstraints = @HttpMethodConstraint(value = "TRACE",

emptyRoleSemantic = EmptyRoleSemantic.DENY))

<security-constraint>

<web-resource-collection>

<url-pattern>...</url-pattern>

<http-method-omission>TRACE</http-method-omission>

</web-resource-collection>

<auth-constraint>

<role-name>Role1</role-name>

</auth-constraint>

</security-constraint>

<security-constraint>

<web-resource-collection>

<url-pattern>...</url-pattern>

<http-method>TRACE</http-method>

</web-resource-collection>

<auth-constraint/>

</security-constraint>

13.4.1.3 映射@HttpConstraint 和@HttpMethodConstraint 为 XML

本节将介绍映射映射@HttpConstraint 和@HttpMethodConstraint 注解值(在@ServletSecurity 中定义使用的)为它们等价的 auth-constraint 和 user-data-constraint 表示,这些注解共用一个通用模型用于表示用在便携式部署描述符中的 auth-constraint 和 user-data-constraint 元素的等价形式。该模型包括以下 3 种元素:

■ emptyRoleSemantic

授权语义, PERMIT 或 DENY,适用于在 rolesAllowed 中没有指定的角色时。此元素的默认值为 PERMIT,且 DENY 不支持与非空的 rolesAllowed 列表结合使用。

■ rolesAllowed

一个包含授权角色的名字列表。当该列表为空时,其含义取决于 emptyRoleSemantic 的值。当角色名字“ *”包含在允许的角色列表中时是没有特别的含义的。 当特殊的角色名字“ **”出现在 rolesAllowed 中时,它表示用户认证,不受约束的角色,是必需的和足够的。 该元素的默认值是一个空列表。

■ transportGuarantee

数据保护需求, NONE 或 CONFIDENTIAL,在连接的请求到达时必须满足。该元素与一个包含一个使用相应值的 transport-guarantee 的 user-data-constraint 是等价的。该元素的默认值是 NONE。

下面的例子展示了上述的@HttpConstraint 模型和 web.xml 中的 auth-constraint 和 user-data-constraint 元素之间的对应关系。

代码示例 13-10 emptyRoleSemantic=PERMIT, rolesAllowed={}, transportGuarantee=NONE

无约束

代码示例 13-11 emptyRoleSemantic=PERMIT, rolesAllowed={}, transportGuarantee=CONFIDENTIAL

<user-data-constraint>

<transport-guarantee>CONFIDENTIAL</transport-guarantee>

</user-data-constraint>

代码示例 13-12 emptyRoleSemantic=PERMIT, rolesAllowed={Role1}, transportGuarantee=NONE

<auth-constraint>

<security-role-name>Role1</security-role-name>

</auth-constraint>

代码示例 13-13 emptyRoleSemantic=PERMIT, rolesAllowed={Role1}, transportGuarantee=CONFIDENTIAL

<auth-constraint>

<security-role-name>Role1</security-role-name>

</auth-constraint>

<user-data-constraint>

<transport-guarantee>CONFIDENTIAL</transport-guarantee>

</user-data-constraint>

101

代码示例 13-14 emptyRoleSemantic=DENY, rolesAllowed={}, transportGuarantee=NONE

<auth-constraint/>

代码示例 13-15 emptyRoleSemantic=DENY, rolesAllowed={}, transportGuarantee=CONFIDENTIAL

<user-data-constraint>

<transport-guarantee>CONFIDENTIAL</transport-guarantee>

</user-data-constraint>

总结: 这段基本上就是对上节说的的注解方式配置在web中的配置实现了

 

13.5 角色

安全角色是由应用开发人员或装配人员定义的逻辑用户分组。当部署了应用,由部署人员映射角色到运行时环境的 principal 或组。

Servlet 容器根据 principal 的安全属性为与进入请求相关的 principal 实施声明式或编程式安全。

这可能以如下任一方式发生:

1. 部署人员已经映射一个安全角色到运行环境中的一个用户组。调用的 principal 所属的用户组取自其安全属性。仅当 principal 所属的用户组由部署人员已经映射了安全角色, principal 是在安全角色中。

2. 部署人员已经映射安全角色到安全策略域中的 principal 名字。在这种情况下,调用的 principal 的名字取自其安全属性。仅当 principal 名字与安全角色已映射到的 principal 名字一样时, principal 是在安全角色中。

13.6 认证

web 客户端可以使用以下机制之一向 web 服务器认证用户身份:

■ HTTP 基本认证( HTTP Basic Authentication)

■ HTTP 摘要认证( HTTP Digest Authentication)

■ HTTPS 客户端认证( HTTPS Client Authentication)

■ 基于表单的认证( Form Based Authentication)

13.6.1 HTTP 基本认证

HTTP 基本认证基于用户名和密码,是 HTTP/1.0 规范中定义的认证机制。 Web 服务器请求 web 客户端认证用户。作为请求的一部分, web 服务器传递 realm(字符串)给要被认证的用户。 Web 客户端获取用户的用户名和密码并传给 web 服务器。 Web 服务器然后在指定的 realm 认证用户。

基本认证是不安全的认证协议。用户密码以简单的 base64 编码发送,且未认证目标服务器。额外的保护可以减少一些担忧:安全传输机制( HTTPS),或者网络层安全(如 IPSEC 协议或 VPN 策略)被应用到一些部署场景。

13.6.2 HTTP 摘要认证

与 HTTP 基本认证类似, HTTP 摘要认证也是基于用户名和密码认证用户,但不像 HTTP 基本认证, HTTP摘要认证不在网络上发生用户密码。在 HTTP 摘要认证中,客户端发送单向散列的密码(和额外的数据)。尽管密码不在线路上发生, HTTP 摘要认证需要对认证容器可用的明文密码等价物(密码等价物可以是这样的,它们仅能在一个特定的 realm 用来认证用户),以致容器可以通过计算预期的摘要验证接收到的认证者。 Servlet 容器应支持 HTTP_DIGEST 身份认证。

13.6.3 基于表单的认证

“登录界面”的外观在使用 web 浏览器的内置的认证机制时不能被改变。本规范引入了所需的基于表单的认证机制,允许开发人员控制登录界面的外观。

Web 应用部署描述符包含登录表单和错误页面条目。登录界面必须包含用于输入用户名和密码的字段。这些字段必须分别命名为 j_username 和 j_password。

当用户试图访问一个受保护的 web 资源,容器坚持用户的认证。如果用户已经通过认证则具有访问资源的权限,请求的 web 资源被激活并返回一个引用。如果用户未被认证,发生所有如下步骤:

1. 与安全约束关联的登录界面被发送到客户端, 且 URL 路径和 HTTP 协议方法触发容器存储的认证。

2. 用户被要求填写表单,包括用户名和密码字段。

3. 客户端 post 表单到服务器。

4. 容器尝试使用来自表单的信息认证用户。

5. 如果认证失败,使用 forward 或 redirect 返回错误页面,且响应状态码设置为 200。 错误页面包含失败信息。

6. 如果授权成功, 客户端使用存储的 URL 路径重定向到资源。

7. 当一个重定向的和已认证的请求到达容器,容器恢复请求和 HTTP 协议方法,且已认证的用户主体被检查看看是否它在已授权的允许访问资源的角色中。

8. 如果用户已授权,容器处理接受的请求。

到达步骤 7 的重定向的请求的 HTTP 协议方法,可以和触发认证的请求有不同的 HTTP 方法。同样地,在第 6 步的重定向之后,表单认证器必须处理重定向的请求,即使对到达请求的 HTTP 方法的认证不是必需的。为了改善重定向的请求的 HTTP 方法的可预测性,容器应该使用 303 状态码( SC_SEE_OTHER)重定向(步骤 6),除了与 HTTP 1.0 用户代理的协作之外的是必需的;在这种情况应该使用 302 状态码。

当进行一个不受保护的传输时,基于表单的认证受制于一些与基本验证一样的相同的脆弱性。

当 触 发 认 证 的 请 求 在 一 个 安 全 传 输 之 上 到 达 , 或 者 登 录 页 面 受 制 于 一 个 CONFIDENTIAL user-data-constraint,登录页面必须返回给用户,并在安全传输之上提交到容器。

登录页面受制于一个 CONFIDENTIAL user-data-constraint,且一个 CONFIDENTIAL user-data-constraint 应该包含在每一个包含认证要求的 security-constraint 中。

HttpServletRequest 接口的 login 方法提供另一种用于应用控制它的登录界面外观的手段。

13.6.3.1 登录表单

基于表单的登录和基于 URL 的 session 跟踪可以通过编程实现。基于表单的登录应该仅被用在当 session 由cookie 或 SSL session 信息维护时。

为了进行适当的认证,登录表单的 action 总是 j_security_check。该限制使得不管请求什么资源,登录表单都能工作,且避免了要求服务器指定输出表单的 action 字段。 登录表单应该在密码表单字段上指定autocomplete=”off”。

下面的示例展示了如何把表单编码到 HTML 页中:

<form method=”POST” action=”j_security_check”>

<input type=”text” name=”j_username”>

<input type=”password” name=”j_password”>

</form>

如果因为 HTTP 请求造成基于表单的登录被调用,容器必须保存原始请求参数,在成功认证时使用,它重定向调用所请求的资源。

如果用户已使用表单登录通过认证, 且已经创建一个 HTTP session,该 session 的超时或失效将导致用户被注销,在这种情况下,随后的请求必须导致用户重新认证。注销与认证具有相同的作用域:例如,如果容器支持单点登录,如 JavaEE 技术兼容的 web 容器,用户只需要与托管在 web 容器中的任何一个 web 应用重新认证即可。

13.6.4 HTTPS 客户端认证

使用 HTTPS( HTTP over SSL)认证最终用户是一种强认证机制。该机制需要客户端拥有 Public KeyCertificate( PKC)。目前, PKCs 在电子商务应用中是很有用的,也对浏览器中的单点登录很有用。

13.6.5 其他容器认证机制

Servlet 容器应该提供公共接口,可用于集成和配置其他的 HTTP 消息层的认证机制,提供给代表已部署应用的容器使用。这些接口应该提供给参与者使用而不是容器供应商(包括应用开发人员、系统管理人员和系统集成人员)。

为了便于实现和集成其他容器认证机制,建议为所有 Servlet 容器实现 Servlet 容器 Profile 的 Javatm 认证 SPI(即, JSR 196)。 SPI 可下载地址: http://www.jcp.org/en/jsr/detail?id=196

13.7 服务器跟踪认证信息

下面的安全标识(如用户和组)在运行时环境中映射的角色是环境指定的而非应用指定的,理想的是:

1. 使登录机制和策略是 web 应用部署到的环境属性。

2. 在同一个容器部署的所有应用能使用相同的认证信息来表示 principal,且

3. 需要重新认证用户仅当已经越过了安全策略域边界。

因此, servlet 容器需要在容器级别(而不是在 web 应用级别)跟踪认证信息。这允许在一个 web 应用已经通过认证的用户可以访问容器管理的以同样的安全标识许可的其他资源。

13.8 指定安全约束

安全约束是一种定义 web 内容保护的声明式方式。安全约束关联授权和或在 web 资源上对 HTTP 操作的用户数据约束。安全约束,在部署描述符中由 security-constraint 表示,其包含以下元素:

■ web 资源集合 (部署描述符中的 web-resource-collection)

■ 授权约束 (部署描述符中的 auth-constraint)

■ 用户数据约束 (部署描述符中的 user-data-constraint)

HTTP 操作和网络资源的安全约束应用(即受限的请求)根据一个或多个 web 资源集合识别。 Web 资源集合包含以下元素:

■ URL 模式 (部署描述符中的 url-pattern)

■ HTTP methods (部署描述符中的 http-method 或 http-method-omission 元素)

授权约束规定认证和命名执行受约束请求的被许可的授权角色的要求。用户必须至少是许可执行受约束请求的命名角色中的一个成员。特殊角色名“ *”是定义在部署描述符中的所有角色名的一种简写。 特殊的角色名“ **”是一种用于任何授权的用户不受约束的角色的速记法。它表示任何授权的用户,不受约束的角色,被授权允许执行约束的请求。 没有指定角色的授权约束表示在任何情况下不允许访问受约束请求。授权约束包含以下元素:

 

■ role name (部署描述符中的 role-name)

用户数据约束规定了在受保护的传输层连接之上接收受约束的请求的要求。需要保护的强度由传输保障的值定义。 INTEGRAL 类型的传输保障用于规定内容完整性要求,且传输保障 CONFIDENTIAL 用于规定保密性要求的。传输保障“ NONE”表示当容器通过任何包括不受保护的连接接受到请求时,必须接受此受约束的请求。 容器可能在响应中强加一个受信的传输保障( confidential transport guarantee)为 INTEGRAL值。 用户数据约束包括如下元素:

■ transport guarantee (部署描述符中的 transport-guarantee)

如果没有授权约束应用到请求,容器必须接受请求,而不要求用户身份认证。如果没有用户数据约束应用到请求,当容器通过任何包括不受保护的连接接收到请求时,必须接受此请求。

13.8.1 组合约束

为了组合约束, HTTP 方法可以说是存在于 web-resource-collection 中,仅当没有在集合中指定 HTTP 方法,或 者 集 合 在 包 含 的 http-method 元 素 中 具 体 指 定 了 HTTP 方 法 , 或 者 集 合 包 含 一 个 或 多 个http-method-omission 元素,但那些没有指定的 HTTP 方法。

当 url-pattern 和 HTTP 方法以组合方式(即,在 web-resource-collection 中)出现在多个安全约束中,该约束(在模式和方法上的)是通过合并单个约束定义的。以相同的模式和方法出现的组合约束规则如下所示:

授权约束组合,其明确指定角色或通过“ *” 隐式指定角色,可产生单个约束的合并的角色名称作为许可的角色。 一个命名角色“ **”的授权约束将与授权约束命名的或隐式的角色组合以允许任何授权的用户不受约束的角色。 不包含授权约束的安全约束将与明确指定角色的或隐式指定角色的允许未授权访问的安全约束合并。授权约束的一个特殊情况是其没有指定角色,将与任何其他约束合并并覆盖它们的作用,这导致访问被阻止。

应用到常见的 url-pattern 和 http-method 的 user-data-constraint 组合, 可产生合并的单个约束接受的连接类型作为接受的连接类型。不包含 user-data-constraint 的安全约束,将与其他 user-data-constraint 合并,使不安全的连接类型是可接受的连接类型。

13.8.2 示例

下面的示例演示了组合约束及它们翻译到的可应用的约束表格。假设部署描述符包含如下安全约束。

<security-constraint>

<web-resource-collection>

<web-resource-name>precluded methods</web-resource-name>

<url-pattern>/*</url-pattern>

<url-pattern>/acme/wholesale/*</url-pattern>

<url-pattern>/acme/retail/*</url-pattern>

<http-method-omission>GET</http-method-omission>

<http-method-omission>POST</http-method-omission>

</web-resource-collection>

<auth-constraint/>

</security-constraint>

106

翻译这个假定的部署描述符将产生定义在表 13-4 中的约束。

表 13-4 安全约束表

url-pattern

http-method

许可的角色

支持的连接类型

<security-constraint>

<web-resource-collection>

<web-resource-name>wholesale</web-resource-name>

<url-pattern>/acme/wholesale/*</url-pattern>

<http-method>GET</http-method>

<http-method>PUT</http-method>

</web-resource-collection>

<auth-constraint>

<role-name>SALESCLERK</role-name>

</auth-constraint>

</security-constraint>

<security-constraint>

<web-resource-collection>

<web-resource-name>wholesale 2</web-resource-name>

<url-pattern>/acme/wholesale/*</url-pattern>

<http-method>GET</http-method>

<http-method>POST</http-method>

</web-resource-collection>

<auth-constraint>

<role-name>CONTRACTOR</role-name>

</auth-constraint>

<user-data-constraint>

<transport-guarantee>CONFIDENTIAL</transport-guarantee>

</user-data-constraint>

</security-constraint>

<security-constraint>

<web-resource-collection>

<web-resource-name>retail</web-resource-name>

<url-pattern>/acme/retail/*</url-pattern>

<http-method>GET</http-method>

<http-method>POST</http-method>

</web-resource-collection>

<auth-constraint>

<role-name>CONTRACTOR</role-name>

<role-name>HOMEOWNER</role-name>

</auth-constraint>

</security-constraint>

/*

所有方法

除 GET, POST

阻止访问

不限制

/acme/wholesale/*

所有方法

除 GET, POST

阻止访问

不限制

/acme/wholesale/*

GET

CONTRACTOR

SALESCLERK

不限制

/acme/wholesale/*

POST

CONTRACTOR

CONFIDENTIAL

/acme/retail/*

所有方法

除 GET, POST

阻止访问

不限制

/acme/retail/*

GET

CONTRACTOR

HOMEOWNER

不限制

/acme/retail/*

POST

CONTRACTOR

HOMEOWNER

不限制

13.8.3 处理请求

当 servlet 容器接收到一个请求,它将使用 119 页“使用 URL 路径”描述的规则来选择在请求 URI 最佳匹配的 url-pattern 上定义的约束(如果有)。如果没有约束被选择,容器将接受该请求。否则,容器将确定在选择的模式上是否此请求的 HTTP 方法是受约束的。如果不是,请求将被接受。否则,请求必须满足在urlpattern 应用到 HTTP 方法的约束。请求被接受和分派到相关的 servlet,必须满足以下两个规则。

1. 接收到的请求的连接特性必须满足至少一种由约束定义的支持的连接类型。如果该规则不满足,容器将拒绝该请求并重定向到 HTTPS 端口。(作为一种优化,容器将以拒绝该请求为 forbidden 并返回 403(SC_FORBIDDEN)状态码,如果知道该访问将最终将被阻止 (通过没有指定角色的授权约束))

2. 请求的认证特性必须满足任何由约束定义的认证和角色要求。如果该规则不能满足是因为访问已经被阻止(通过没有指定角色的授权约束),则请求将被拒绝为 forbidden 并返回 403 (SC_FORBIDDEN)状态码。

如 果 访 问 是 受 限 于 许 可 的 角 色 且 请 求 还 没 有 被 认 证 , 则 请 求 将 被 拒 绝 为 unauthorized 且401(SC_UNAUTHORIZED)状态码将被返回以导致身份认证。如果访问是受限于许可的角色且请求的认证身份不是这些角色中的成员,则请求将被拒绝为 forbidden 且 403 状态码(SC_FORBIDDEN)将被返回到用户。

13.8.4 未覆盖的 HTTP 协议方法

security-constraint schema 提供了枚举(包括省略)定义在 security-constraint 中的保护要求应用到哪一个 HTTP方法的能力。当 HTTP 方法枚举在 security-constraint,约束定义的保护仅应用到枚举建立的方法。我们把不是枚举建立的方法称为“未覆盖的” HTTP 方法。未覆盖的 HTTP 方法不保护所有 security-constraint 的url-pattern 最匹配的请求的 URL。

当 HTTP 方法没有枚举在一个 security-constraint 中时,约束定义的保护应用到完整的 HTTP(扩展)方法集。在那种情况,在那些 security-constraint 的 url-pattern 最佳匹配的所有请求的 URL,没有未覆盖的 HTTP方法。

例子用三种方式描述了在哪些 HTTP 协议方法可能未覆盖。方法是否是未覆盖的是由在所有约束应用到一个 url-pattern 已经按照 13-143 页的 13.8.1 节, “组合约束”组合决定的。

1. security-constraint 在 http-method 元素中命名一个或多个 HTTP 方法。除了那些明明在约束中的,所有 HTTP方法是未覆盖的。

<security-constraint>

<web-resource-collection>

<web-resource-name>wholesale</web-resource-name>

<url-pattern>/acme/wholesale/*</url-pattern>

<http-method>GET</http-method>

</web-resource-collection>

<auth-constraint>

<role-name>SALESCLERK</role-name>

</auth-constraint>

</security-constraint>

除了 GET,所以 HTTP 方法是未覆盖的。

2. security-constriant 在 http-method-omission 元素中命名一个或多个 HTTP 方法。所有命名在约束中的 HTTP

方法是未覆盖的。

<security-constraint>

<web-resource-collection>

<web-resource-name>wholesale</web-resource-name>

<url-pattern>/acme/wholesale/*</url-pattern>

<http-method-omission>GET</http-method-omission>

</web-resource-collection>

<auth-constraint/>

</security-constraint>

GET 是未覆盖的。所有其他方法是被排除的 auth-constraint 覆盖的。

3. 包括一个@@HttpConstraint 的@ServletSecurity 注解返回所有默认值,且也包括至少一个返回除了所有默认值之外的@HttpMethodConstraint。除了那些命名在@HttpMethodConstraint 中的所有 HTTP 方法是被注解未覆盖的。这种情况是与情况 1 是类似的,且等价于使用 ServletRegistration 接口的 setServletSecurity 方法也将产生一个类似的结果。

@ServletSecurity((httpMethodConstraints = {

@HttpMethodConstraint(value = "GET", rolesAllowed = "R1"), @HttpMethodConstraint(value = "POST",rolesAllowed = "R1", transportGuarantee = TransportGuarantee.CONFIDENTIAL) })

public class Example5 extends HttpServlet {

}

除了 GET 和 POST 之外的所有 HTTP 方法是未覆盖的。

13.8.4.1 安全约束配置规则

目的:确保在所有约束的 URL 模式上的所有 HTTP 方法有预期的安全保护(即,覆盖的)。

1. 没有在约束中命名 HTTP 方法;在这种情况下,未 URL 模式定义的安全保护将应用到所有 HTTP 方法。

2. 如果你不能遵循规则#1,添加<deny-uncovered-http-methods>和声明(使用<http-method>元素,或等价的注解)所有在约束 URL 模式允许的 HTTP 方法(有安全保护)。

3. 如果你 不能遵 循规 则#2,声明 约束来 覆盖 每一个 约束 的 URL 模式的所有 HTTP 方法。 使用

<http-method-omission> 元 素 或 HttpMethodConstraint 注 解 来 表 示 除 了 被 <http-method> 或

HttpMethodConstraint 命名的那些之外的所有 HTTP 方法集。当使用注解时,使用 HttpConstraint 定义应用到所有其他 HTTP 方法和配置 EmptyRoleSemantic=DENY 来导致所有其他 HTTP 方法被拒绝的安全语义。

13.8.4.2 处理未覆盖的 HTTP 方法

在应用部署期间,容器必须通知部署人员任何存在于从为应用定义的约束组合产生的应用安全约束配置中的未覆盖的 HTTP 方法。提供的信息必须标识未覆盖的 HTTP 协议方法,和在 HTTP 方法未覆盖那些相关的 URL 模式。通知部署人员的要求可以通过记录必需的信息来满足。

当 deny-uncovered-http-methods 标记在应用的 web.xml 中设置了,容器必须拒绝任何 HTTP 协议方法,当它用于一个其 HTTP 方法在应用到请求 URL 最佳匹配的 url-pattern 的组合安全约束请求 URL 是未覆盖的。

拒绝的请求将被拒绝为 forbidden 并返回一个 403( SC_FORBIDDEN)状态码。

导致未覆盖的 HTTP 方法为拒绝,部署系统将建立额外的排除 auth-constraint,去覆盖这些在未覆盖的 HTTP方法约束的 url-pattern 的 HTTP 方法。

当应用的安全配置不包含未覆盖的方法, deny-uncovered-http-methods 标记在应用的有效的安全配置上必须没有效果。

应用 deny-uncovered-http-methods 到一个应用,其安全配置包含未覆盖的方法,可能,在一些情况下,拒绝访问资源为了应用的功能必须是可访问的。这这种情况下,应用的安全配置应该完成所有未覆盖的方法被相关约束配置覆盖。

应 用 开 发 人 员 应 该 定 义 安 全 约 束 配 置 , 没 有 任 何 未 覆 盖 的 HTTP 方 法 , 且 他 们 应 该 设 置deny-uncovered-http-methods 标记确保他们的应用不会依赖于通过未覆盖的方法来得到可访问性。Servlet 容器可以提供一个配置选项来选择未覆盖方法的默认行为是 ALLOW 还是 DENY。这个选项可以配置在每容器粒度或更大。注意,设置这个默认为 DENY 可能导致一些应用失败。

13.9 默认策略

默认情况下,身份认证并不需要访问资源。当安全约束(如果有)包含的 url-pattern 是请求 URI 的最佳匹配,且结合了施加在请求的 HTTP 方法上的 auth-constraint(指定的角色),则身份认证是需要的。同样,一个受保护的传输是不需要的,除非应用到请求的安全约束结合了施加在请求的 HTTP 方法上的user-data-constraint(有一个受保护的 transport-guarantee)。

13.10 登录和退出

容器在分派请求到 servlet 引擎之前建立调用者身份。在整个请求处理过程中或直到应用成功的在请求上调用身份认证、登录或退出,调用者身份保持不变。对于异步请求,调用者身份建立在初始分派时,直到整个请求处理完成或直到应用成功的在请求上调用身份认证、登录或退出,调用者身份保持不变。在处理请求时登录到一个应用,精确地对应有一个有效的非空的与请求关联的调用者身份,可以通过调用请求的 getRemoteUser 或 getUserPrincipal 确定。这些方法的任何一个返回 null 值表示调用者没有登录到处理请求的应用。

容器可以创建 HTTP Session 对象用于跟踪登录状态。如果开发人员创建一个 session 而用户没有进行身份认证,然后容器认证用户,登录后,对开发人员代码可见的 session 必须是相同的 session 对象,该 session 是登录发生之前创建的,以便不丢失 session 信息

 

对于这部分说明除了可以了解下13.8.3 处理请求 servlet处理方式外,其他没什么有用的价值

这里总结下这部分比较重要的几个概念,对理解spring-security 有点帮助:

1: 角色 在规范中,角色的定义是通过web.xml定义的

servlet的权限控制都是以角色为基础的

2: 用户 远端请求访问的用户名 根据用户名判断是否已经登录,这个用户名可以是在代码里面写死的,可以是通过form表单传递的,form表单传递的话,字段名必须是j_username

3: 认证通过后,第二次则是通过session获取登录名称的

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值