次のように、ユーザーのロールの階層セットを定義する Spring ベースのアプリケーションがあります。
<bean id="roleHierarchy" class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
<property name="hierarchy">
<value>
ROLE_ROOT > ROLE_SUDOER
ROLE_SUDOER > ROLE_USER
ROLE_USER > ROLE_DUMB
</value>
</property>
</bean>
私のAccessDecisionManagerでは、このように4人の投票者を使用しています:
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
<constructor-arg>
<list>
<bean class="org.springframework.security.web.access.expression.WebExpressionVoter" />
<bean class="org.springframework.security.oauth2.provider.vote.ScopeVoter" />
<bean id="roleVoter" class="org.springframework.security.access.vote.RoleHierarchyVoter">
<constructor-arg ref="roleHierarchy" />
</bean>
<bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
</list>
</constructor-arg>
</bean>
<sec:global-method-security pre-post-annotations="enabled">
<sec:expression-handler ref="methodSecurityExpressionHandler"/>
</sec:global-method-security>
この一連の階層ロールを構成したにもかかわらず、最上位のロールROLE_ROOTを持つユーザーが次のコントローラーで/myUrl url にアクセスしようとすると、 ACCESS DENIED例外が発生します。
@Controller
@PreAuthorize("hasRole('ROLE_SUDOER')")
@RequestMapping(value = "/myUrl")
public class BuggyController extends AbstractController {
@RequestMapping(value = "", method = RequestMethod.GET)
@ResponseBody
public List<SensitiveItem> getSensitiveItems(final Principal principal)
{
// removed for brievety
}
}
これがスタックトレースです(実際にはその一部です):
10:55:16.012 [ajp-bio-8029-exec-4] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - [ ] - Authorization successful
10:55:16.012 [ajp-bio-8029-exec-4] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - [ ] - RunAsManager did not change Authentication object
10:55:16.013 [ajp-bio-8029-exec-4] DEBUG o.s.s.a.i.a.MethodSecurityInterceptor - [ 192.168.xx.yyy] - Secure object: ReflectiveMethodInvocation: public java.util.List com.xxxx.yyyy.BuggyController.getSensitiveItems(java.security.Principal); target is of class [com.xxxx.yyyy.BuggyController.getSensitiveItems]; Attributes: [[authorize: 'hasRole('ROLE_SUDOER')', filter: 'null', filterTarget: 'null']]
10:55:16.013 [ajp-bio-8029-exec-4] DEBUG o.s.s.a.i.a.MethodSecurityInterceptor - [ 192.168.xx.yyy] - Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@8bc6b2e4: Principal: org.springframework.security.core.userdetails.User@7a85da9c: Username: sudoer; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_ROOT; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@2cd90: RemoteIpAddress: 192.168.22.112; SessionId: 8CE7068F50AD373ED2194B76A188BCEF; Granted Authorities: ROLE_ROOT
10:55:16.013 [ajp-bio-8029-exec-4] DEBUG o.s.s.a.h.RoleHierarchyImpl - [ 192.168.xx.yyy] - getReachableGrantedAuthorities() - From the roles [ROLE_ROOT] one can reach [ROLE_ROOT, ROLE_SUDOER, ROLE_USER, ROLE_DUMB] in zero or more steps.
10:55:16.013 [ajp-bio-8029-exec-4] DEBUG o.s.s.access.vote.AffirmativeBased - [ 192.168.xx.yyy] - Voter: org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter@65685e97, returned: -1
10:55:16.013 [ajp-bio-8029-exec-4] DEBUG o.s.s.access.vote.AffirmativeBased - [ 192.168.xx.yyy] - Voter: org.springframework.security.access.vote.RoleVoter@29800e27, returned: 0
10:55:16.013 [ajp-bio-8029-exec-4] DEBUG o.s.s.access.vote.AffirmativeBased - [ 192.168.xx.yyy] - Voter: org.springframework.security.access.vote.AuthenticatedVoter@162137ba, returned: 0
10:55:16.015 [ajp-bio-8029-exec-4] WARN c.d.d.utils.ExceptionResolver - [ 192.168.xx.yyy] - catched an exception: Access is denied
org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:83) ~[spring-security-core-3.1.3.RELEASE.jar:3.1.3.RELEASE]
ログは、 ROLE_ROOT がROLE_SUDOERにエスカレートできることを明確に示しています。
10:55:16.013 [ajp-bio-8029-exec-4] DEBUG o.s.s.a.h.RoleHierarchyImpl - [ 192.168.xx.yyy] - getReachableGrantedAuthorities() - From the roles [ROLE_ROOT] one can reach [ROLE_ROOT, ROLE_SUDOER, ROLE_USER, ROLE_DUMB] in zero or more steps.
私の質問は、ROLE_SUDOER がより優先度の高いロール (ここでは ROLE_ROOT) から到達可能である場合、なぜ私の呼び出しが失敗するのですか?
実行するには、メソッドのセキュリティ制御式の一部として、最上位のロール ROLE_ROOT を明示的に追加する必要がありました。
@Controller
@PreAuthorize("hasAnyRole('ROLE_ROOT', 'ROLE_SUDOER')")
@RequestMapping(value = "/myUrl")
public class BuggyController extends AbstractController {
@RequestMapping(value = "", method = RequestMethod.GET)
@ResponseBody
public List<SensitiveItem> getSensitiveItems(final Principal principal)
{
// removed for brievety
}
}
階層的な役割セットが巨大な場合、非常に複雑になる可能性があるため、これは本当にばかげています。階層的な役割はまさにそのためのものです。優先度の高い役割に優先度の低い役割を含めることができるように、効率的な役割のセキュリティ制御が可能になります。
誰かがこの問題について私を助けることができますか? 前もって感謝します。