首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >测试弹簧安全性

测试弹簧安全性
EN

Stack Overflow用户
提问于 2012-08-03 19:26:44
回答 2查看 705关注 0票数 2

我已经使用Spring安全保护了我的服务器,并尝试测试它。我的测试包括登录测试用户(在DB中已经存在),然后尝试访问一个安全URL,该URL要求用户进行身份验证,并具有特定的角色。

这是我的密码

我创建了一个安全上下文:

代码语言:javascript
复制
<!-- URL's that start with the "app/secured" prefix requires authentication -->
<http auto-config="false" use-expressions="true">
    <form-login login-processing-url="/app/login"
        authentication-success-handler-ref="ajaxAuthenticationSuccessHandler"
        authentication-failure-handler-ref="ajaxAuthenticationFailureHandler" />
    <intercept-url pattern="/**" access="permitAll" />
    <intercept-url pattern="**/app/secured/**" access="isAuthenticated()" />
</http>

<authentication-manager alias="authenticationManager">
    <authentication-provider user-service-ref="myUserDetailsService">
        <password-encoder ref="passwordEncoder">
            <salt-source user-property="creationTime" />
        </password-encoder>
    </authentication-provider>
</authentication-manager>

<beans:bean id="passwordEncoder"
    class="me.co.server.bl.security.ExtendedShaPasswordEncoder" />

<beans:bean id="ajaxAuthenticationSuccessHandler"
    class="me.co.server.web.resource.register.login.AjaxAuthenticationSuccessHandler" />

<beans:bean id="ajaxAuthenticationFailureHandler"
    class="me.co.server.web.resource.register.login.AjaxAuthenticationFailureHandler" />

<beans:bean id="myUserDetailsService"
    class="me.co.server.bl.security.MyUserDetailsService" />

我在我的web.xml顶部添加了安全上下文和安全过滤器:

代码语言:javascript
复制
<!-- Spring Security -->
<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
    /WEB-INF/spring/applicationContext.xml
    /WEB-INF/spring/security-context.xml
    </param-value>
</context-param>

以下是我的web层泽西实现:

代码语言:javascript
复制
@Path("/secured/{resourceName}")
@Component
public class SecuredResourceProvider extends ServiceResourceProvider {

    /*--- Members ---*/

    private ILogger logger = LogManager.getLogger(SecuredResourceProvider.class);

    @Inject
    protected SecuredResourceFactory securedResourceFactory;

    /*--- Constructors ---*/

    protected SecuredResourceProvider() {
    super("Secured");
    }

    /*--- Public Methods ---*/

    @GET
    @Produces("application/json")
    @Path("/{resourceId}")
    public String getSecuredResource(@PathParam("resourceId") String resourceId, @PathParam("resourceName") String resourceName)
        throws UnhandledResourceException, UnauthorizedAccessException, ServerInternalErrorException, JsonException, ResourceArgumentException {

    // NOT IMPLEMENTED AT THE MOMENT //

    return null;
    }

    @PUT
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.TEXT_PLAIN)
    @Path("/{code}")
    public String putSecuredResource(String resourceData, @PathParam("code") String ownerResourceId, @PathParam("resourceName") String resourceName)
        throws UnhandledResourceException, UnauthorizedAccessException, ServerInternalErrorException, JsonException, ResourceArgumentException {

    if (SecuredResources.isSecuredResource(resourceName)) {
        IResource<String> resource = securedResourceFactory.getResourceInstance(resourceName);

        String resourceString = resource.put(ownerResourceId, resourceData);
        return createReturnResourceString(resourceString);
    } else {
        throw new UnhandledResourceException("Invoking a secured method for an unsecured resource " + resourceName);
    }
    }


    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.TEXT_PLAIN)
    @Path("/{resourceId}")
    public String postSecuredResource(String resourceData, @PathParam("resourceName") String resourceName, @PathParam("resourceId") String resourceId)
        throws UnhandledResourceException, UnauthorizedAccessException, ServerInternalErrorException, JsonException, ResourceArgumentException {

    if (SecuredResources.isSecuredResource(resourceName)) {
        IResource<String> resource = securedResourceFactory.getResourceInstance(resourceName);
        String resourceString = resource.post(resourceId, resourceData);
        return createReturnResourceString(resourceString);
    } else {
        throw new UnhandledResourceException("Invoking a secured method for an unsecured resource " + resourceName);
    }
    }


    @DELETE
    @Consumes(MediaType.TEXT_PLAIN)
    @Produces(MediaType.TEXT_PLAIN)
    @Path("/{code}")
    public String deleteSecuredResource(String resourceId, @PathParam("code") String ownerResourceId, @PathParam("resourceName") String resourceName)
        throws UnhandledResourceException, UnauthorizedAccessException, ServerInternalErrorException, JsonException, ResourceArgumentException {

    if (SecuredResources.isSecuredResource(resourceName)) {
        IResource<String> resource = securedResourceFactory.getResourceInstance(resourceName);

        String resourceString = resource.delete(ownerResourceId, resourceId);
        return createReturnResourceString(resourceString);
    } else {
        throw new UnhandledResourceException("Invoking a secured method for an unsecured resource " + resourceName);
    }
    }
}

这里没有什么特别之处,只是根据我的url的拦截定义,这个spring应该是安全的(需要经过身份验证的用户)。web层将请求委托给业务逻辑层,业务逻辑层使用方法-安全注释进行安全保护:

代码语言:javascript
复制
    @Override
    @Secured("ROLE_BRAND_MANAGER")
    public String post(String gymCode, String trainingSessionJson) throws UnhandledResourceException, ServerInternalErrorException,
        ResourceArgumentException, JsonException {

...

}

为此,我将全局方法安全声明添加到我的application-context中。

代码语言:javascript
复制
<security:global-method-security secured-annotations="enabled" proxy-target-class="true"/>

发布的用户是一个品牌经理(据权威人士所知),但目前没有持久化,而是从实体返回硬编码:

代码语言:javascript
复制
@Entity
@Table(name = "brand_managers")
public class BrandManager implements Serializable, UserDetails {

    /** Serial version unique id */
    private static final long serialVersionUID = -7992146584570782015L;

    public static final String ROLE = "ROLE_BRAND_MANAGER";

    /*--- Members ---*/

    /** The unique, internal ID of the entity. */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private long id;

    /**
     * The creation time of this user
     */
    @Column(name = "creation_time")
    protected long creationTime;

    /**
     * The hashed password
     */
    @Column(name = "password")
    protected String password;

    @Column(name = "first_name")
    protected String firstName;

    @Column(name = "last_name")
    protected String lastName;

    @Column(name = "email")
    protected String eMail;

    @Column(name = "address1")
    protected String address1;

    @Column(name = "address2", nullable = true)
    protected String address2;

    @Column(name = "city")
    protected String city;

    @Column(name = "state")
    protected String state;

    @Column(name = "zip", nullable = true)
    protected String zip;

    @Column(name = "country")
    protected String country;

    @Column(name = "phone")
    protected String phone;

    @Column(name = "brand_id")
    protected int brandId;

    /*--- Constructors ---*/

    /**
     * default
     */
    public BrandManager() {
    setCreationTime(Calendar.getInstance().getTimeInMillis());
    }

    public BrandManager(String password, String firstName, String lastName, String eMail, String address1, String address2, String city,
        String state, String zip, String country, String phone, int brandId) {
    this();
    this.password = password;
    this.firstName = firstName;
    this.lastName = lastName;
    this.eMail = eMail;
    this.address1 = address1;
    this.address2 = address2;
    this.city = city;
    this.state = state;
    this.zip = zip;
    this.country = country;
    this.phone = phone;
    this.brandId = brandId;
    }

    /*--- Overridden Methods ---*/

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
    // currently not holding authorities in DB, but returning hard-coded
    return AuthorityUtils.createAuthorityList(ROLE);
    }
... getter and setters...

}

我的UserDetailsService简单地从DB加载用户(使用dao委托)。

现在,当我测试我的服务器(运行在tomcat中)并调用安全URL时,我看到了一些奇怪的东西。我在AffirmativeBased类的“决定”方法中放置了一个断点,这是security的DecisionManager的默认实现:

公共无效判定(身份验证、对象对象、集合configAttributes)抛出AccessDeniedException { int = 0;

代码语言:javascript
复制
for (AccessDecisionVoter voter : getDecisionVoters()) {
    int result = voter.vote(authentication, object, configAttributes);

    if (logger.isDebugEnabled()) {
        logger.debug("Voter: " + voter + ", returned: " + result);
    }

    switch (result) {
    case AccessDecisionVoter.ACCESS_GRANTED:
        return;

    case AccessDecisionVoter.ACCESS_DENIED:
        deny++;

        break;

    default:
        break;
    }
}

当调用我的服务方法时,它使用@Secured注释进行注释,并且我看到"configAttributes“属性包含一个值为permitAll的元素,这不是我所期望看到的。我希望能看到"ROLE_BRAND_MANAGER“。我调试错地方了吗?我如何知道我的安全相关代码是正确的?

提前谢谢你,瑜伽

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-08-06 06:58:33

如php-编码器所建议的:

第一条规则总是占上风,所以我建议重新排序拦截-url-s,并将permitAll移到最后。

我不得不改变我的url截取定义的顺序,现在这个流程是有意义的。

票数 0
EN

Stack Overflow用户

发布于 2012-08-03 23:35:40

实际上,在这样的命名空间配置中有两个AccessDecisionManager实例。一种用于web安全,另一种用于方法安全。如果需要,两者都可以被重写。

您的断点可能意味着您正在看到web安全性之一(如果您在调试器中检查堆栈,这一点应该很明显)。

确保global-method-security与您想要保护的bean位于同一个上下文文件中。Security中有更多信息,您还可以找到关于父/子Spring上下文文件的其他讨论。通常,如果您想保护在dispatcher servlet配置文件(例如spring-servlet.xml)中声明的MVC控制器或其他web bean,那么它也应该在其中。从主应用程序上下文(由ContextLoaderListenerweb.xml中加载的应用程序上下文)中看不到它们,因此如果将方法安全性元素放在其中,它将无法工作。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11802071

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档