[解決済み] SecurityContextにAuthenticationオブジェクトが見つかりませんでした - Spring 3.2.2
質問
を実装しているクラスからprotectedメソッドを呼び出そうとしています。
ApplicationListener<AuthenticationSuccessEvent>
インターフェイスを使用します (Spring 3.2.2 および Spring Security 3.2.0 M1)。
これは
が前回の質問です。
アプリケーションは以下の環境で動作しています。
- Spring 3.2.2
- Spring Security 3.2.0
- JPA 2.0
- JSF 2.1.9
- MySQL 5.6.11
- JDK-7u11
- NetBeans 7.2.1
Springのセキュリティに関連する以下のライブラリをクラスパスに追加しています。
- spring-security-core-3.2.0.M1.jar
- 春セキュリティーコンフィグ-3.2.0.M1.jar
- Spring-security-web-3.2.0.M1.jar
を実装したクラスです。
ApplicationListener<AuthenticationSuccessEvent>
は以下の通りです。
package loginsuccesshandler;
import admin.dao.service.StateService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
import org.springframework.stereotype.Service;
@Service
public final class AuthSuccessHandler implements ApplicationListener<AuthenticationSuccessEvent>
{
@Autowired
private StateService stateService;
@Override
public void onApplicationEvent(AuthenticationSuccessEvent event)
{
System.out.println(event.getAuthentication());
System.out.println("rowCount = "+stateService.rowCount());
}
}
これにより、正しい認証情報を持つユーザーであっても、以下のようなメッセージでログインできなくなります(あくまで例です。認証に成功したときの状態の数を数えることは全く必要ありません)。
<ブロッククオートSecurityContext に Authentication オブジェクトが見つかりませんでした。
イベントが発生します。の中の最初のステートメントは
onApplicationEvent()
メソッドは次のように表示します。
org.springframework.security.authentication.UsernamePasswordAuthenticationToken@45264a59: Principal: org.springframework.security.core.userdetails.User@586034f:Username: admin;
Password: [PROTECTED];
Enabled: true;
AccountNonExpired: true;
credentialsNonExpired: true;
AccountNonLocked: true;
Granted Authorities: ROLE_ADMIN;
Credentials: [PROTECTED];
Authenticated: true;
Details: org.springframework.security.web.authentication.WebAuthenticationDetails@380f4: RemoteIpAddress: 127.0.0.1;
SessionId: 88777A678DC5BB0272F84CA4BC61FAF2;
Granted Authorities: ROLE_ADMIN
つまり、ユーザーが認証され、認証オブジェクトが利用できるようになったようです。
私の
springSecurity.xml
ファイルは単純に以下のようなものです。
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<http pattern="/utility/Login.jsf*" security="none"/>
<debug/>
<http auto-config='true' use-expressions="true" disable-url-rewriting="true">
<session-management session-fixation-protection="newSession">
<concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
</session-management>
<intercept-url pattern="/admin_side/**" access="hasRole('ROLE_ADMIN')" requires-channel="any"/>
<intercept-url pattern="/utility/Login.jsf" access="permitAll" requires-channel="any"/>
<http-basic />
<anonymous />
<form-login login-processing-url="/j_spring_security_check" login-page="/utility/Login.jsf" authentication-success-handler-ref="loginSuccessHandler" authentication-failure-handler-ref="authenticationFailureHandler"/>
<logout logout-success-url="/utility/Login.jsf" invalidate-session="true" delete-cookies="JSESSIONID"/>
</http>
<authentication-manager>
<authentication-provider>
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="select email_id, password, enabled from user_table where lower(email_id)=lower(?)"
authorities-by-username-query="select ut.email_id, ur.authority from user_table ut, user_roles ur where ut.user_id=ur.user_id and lower(ut.email_id)=lower(?)"/>
</authentication-provider>
</authentication-manager>
<beans:bean id="loginSuccessHandler" class="loginsuccesshandler.LoginSuccessHandler"/>
<beans:bean id="authenticationFailureHandler" class="loginsuccesshandler.AuthenticationFailureHandler" />
<global-method-security secured-annotations="enabled" pre-post-annotations="enabled" proxy-target-class="false">
<protect-pointcut expression="execution(* admin.dao.*.*(..))" access="ROLE_ADMIN"/>
</global-method-security>
</beans:beans>
以下のXMLを省略した場合、Springセキュリティは正常に動作します。
spring-security.xml
ファイルを作成します。
<global-method-security secured-annotations="enabled" proxy-target-class="false">
<protect-pointcut expression="execution(* admin.dao.*.*(..))" access="ROLE_ADMIN"/>
</global-method-security>
を実装したクラスから、(メソッドセキュリティを適用した)protected メソッドを呼び出すことはできますか?
ApplicationListener<AuthenticationSuccessEvent>
インターフェイスはありますか?もしそうなら、私の場合何が足りないのでしょうか?これまで何千ものリンクをクリックしましたが、手がかりは一つも見つかりませんでした。
その
application-context.xml
ファイルを作成します。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<context:component-scan base-package="admin.mangedbean loginsuccesshandler" use-default-filters="false">
<context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
<context:include-filter expression="org.springframework.web.bind.annotation.ControllerAdvice" type="annotation"/>
</context:component-scan>
<mvc:annotation-driven/>
<context:annotation-config/>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory" >
<property name="jpaProperties">
<props>
<prop key="hibernate.enable_lazy_load_no_trans">true</prop>
</props>
</property>
<property name="jpaPropertyMap">
<map>
<entry key="eclipselink.weaving" value="false"/>
</map>
</property>
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/social_networking"/>
</bean>
<!--The bean shown in the beginning is configured here-->
<bean id="authSuccessHandler" class="loginsuccesshandler.AuthSuccessHandler"/>
<bean id="testService" class="admin.dao.TestDAO"/>
<bean id="stateService" class="admin.dao.StateDAO"/>
<bean id="sharableService" class="admin.dao.SharableDAO"/>
</beans>
は
web.xml
ファイルを作成します。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext.xml
/WEB-INF/spring-security.xml
</param-value>
</context-param>
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<!--<param-value>Development</param-value>-->
<param-value>Production</param-value>
</context-param>
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>/WEB-INF/log4j.properties</param-value>
</context-param>
<context-param>
<param-name>log4jExposeWebAppRoot</param-name>
<param-value>false</param-value>
</context-param>
<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>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<security-constraint>
<display-name>Restrict direct access to XHTML files</display-name>
<web-resource-collection>
<web-resource-name>XHTML files</web-resource-name>
<url-pattern>*.xhtml</url-pattern>
</web-resource-collection>
<auth-constraint />
</security-constraint>
<session-config>
<session-timeout>
120
</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>/utility/Login.jsf</welcome-file>
</welcome-file-list>
<resource-ref>
<res-ref-name>jdbc/social_networking</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
</web-app>
ログインに失敗した場合のデバッグ情報は、以下のとおりです。
DEBUG [http-apr-8080-exec-55] (AntPathRequestMatcher.java:116) - Checking match of request : '/j_spring_security_check'; against '/utility/login.jsf*'
DEBUG [http-apr-8080-exec-55] (AntPathRequestMatcher.java:116) - Checking match of request : '/j_spring_security_check'; against '/utility/login.jsf*'
DEBUG [http-apr-8080-exec-55] (FilterChainProxy.java:337) - /j_spring_security_check at position 1 of 13 in additional filter chain; firing Filter: 'ChannelProcessingFilter'
DEBUG [http-apr-8080-exec-55] (AntPathRequestMatcher.java:116) - Checking match of request : '/j_spring_security_check'; against '/admin_side/**'
DEBUG [http-apr-8080-exec-55] (AntPathRequestMatcher.java:116) - Checking match of request : '/j_spring_security_check'; against '/utility/login.jsf'
DEBUG [http-apr-8080-exec-55] (FilterChainProxy.java:337) - /j_spring_security_check at position 2 of 13 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
DEBUG [http-apr-8080-exec-55] (HttpSessionSecurityContextRepository.java:139) - HttpSession returned null object for SPRING_SECURITY_CONTEXT
DEBUG [http-apr-8080-exec-55] (HttpSessionSecurityContextRepository.java:85) - No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@1103da5. A new one will be created.
DEBUG [http-apr-8080-exec-55] (FilterChainProxy.java:337) - /j_spring_security_check at position 3 of 13 in additional filter chain; firing Filter: 'ConcurrentSessionFilter'
DEBUG [http-apr-8080-exec-55] (FilterChainProxy.java:337) - /j_spring_security_check at position 4 of 13 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
DEBUG [http-apr-8080-exec-55] (FilterChainProxy.java:337) - /j_spring_security_check at position 5 of 13 in additional filter chain; firing Filter: 'LogoutFilter'
DEBUG [http-apr-8080-exec-55] (FilterChainProxy.java:337) - /j_spring_security_check at position 6 of 13 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
DEBUG [http-apr-8080-exec-55] (AbstractAuthenticationProcessingFilter.java:189) - Request is to process authentication
DEBUG [http-apr-8080-exec-55] (ProviderManager.java:152) - Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
DEBUG [http-apr-8080-exec-55] (JdbcTemplate.java:637) - Executing prepared SQL query
DEBUG [http-apr-8080-exec-55] (JdbcTemplate.java:572) - Executing prepared SQL statement [select email_id, password, enabled from user_table where lower(email_id)=lower(?)]
DEBUG [http-apr-8080-exec-55] (DataSourceUtils.java:110) - Fetching JDBC Connection from DataSource
DEBUG [http-apr-8080-exec-55] (DataSourceUtils.java:327) - Returning JDBC Connection to DataSource
DEBUG [http-apr-8080-exec-55] (JdbcTemplate.java:637) - Executing prepared SQL query
DEBUG [http-apr-8080-exec-55] (JdbcTemplate.java:572) - Executing prepared SQL statement [select ut.email_id, ur.authority from user_table ut, user_roles ur where ut.user_id=ur.user_id and lower(ut.email_id)=lower(?)]
DEBUG [http-apr-8080-exec-55] (DataSourceUtils.java:110) - Fetching JDBC Connection from DataSource
DEBUG [http-apr-8080-exec-55] (DataSourceUtils.java:327) - Returning JDBC Connection to DataSource
DEBUG [http-apr-8080-exec-55] (AbstractBeanFactory.java:246) - Returning cached instance of singleton bean 'authSuccessHandler'
DEBUG [http-apr-8080-exec-55] (AbstractBeanFactory.java:246) - Returning cached instance of singleton bean 'org.springframework.security.core.session.SessionRegistryImpl#0'
DEBUG [http-apr-8080-exec-55] (AbstractFallbackTransactionAttributeSource.java:106) - Adding transactional method 'rowCount' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly; ''
DEBUG [http-apr-8080-exec-55] (DelegatingMethodSecurityMetadataSource.java:65) - Caching method [CacheKey[admin.dao.StateDAO; public abstract java.lang.Long admin.dao.service.StateService.rowCount()]] with attributes [ROLE_ADMIN]
DEBUG [http-apr-8080-exec-55] (AbstractBeanFactory.java:246) - Returning cached instance of singleton bean 'transactionManager'
DEBUG [http-apr-8080-exec-55] (AbstractPlatformTransactionManager.java:366) - Creating new transaction with name [admin.dao.StateDAO.rowCount]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly; ''
DEBUG [http-apr-8080-exec-55] (JpaTransactionManager.java:369) - Opened new EntityManager [org.hibernate.ejb.EntityManagerImpl@84ff11] for JPA transaction
DEBUG [http-apr-8080-exec-55] (JpaTransactionManager.java:408) - Not exposing JPA transaction [org.hibernate.ejb.EntityManagerImpl@84ff11] as JDBC transaction because JpaDialect [org.springframework.orm.jpa.DefaultJpaDialect@d9dbb8] does not support JDBC Connection retrieval
DEBUG [http-apr-8080-exec-55] (AbstractSecurityInterceptor.java:194) - Secure object: ReflectiveMethodInvocation: public abstract java.lang.Long admin.dao.service.StateService.rowCount(); target is of class [admin.dao.StateDAO]; Attributes: [ROLE_ADMIN]
DEBUG [http-apr-8080-exec-55] (AbstractBeanFactory.java:246) - Returning cached instance of singleton bean 'authSuccessHandler'
DEBUG [http-apr-8080-exec-55] (AbstractBeanFactory.java:246) - Returning cached instance of singleton bean 'org.springframework.security.core.session.SessionRegistryImpl#0'
DEBUG [http-apr-8080-exec-55] (AbstractPlatformTransactionManager.java:844) - Initiating transaction rollback
DEBUG [http-apr-8080-exec-55] (JpaTransactionManager.java:534) - Rolling back JPA transaction on EntityManager [org.hibernate.ejb.EntityManagerImpl@84ff11]
DEBUG [http-apr-8080-exec-55] (JpaTransactionManager.java:594) - Closing JPA EntityManager [org.hibernate.ejb.EntityManagerImpl@84ff11] after transaction
DEBUG [http-apr-8080-exec-55] (EntityManagerFactoryUtils.java:338) - Closing JPA EntityManager
DEBUG [http-apr-8080-exec-55] (AbstractAuthenticationProcessingFilter.java:346) - Authentication request failed: org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext
DEBUG [http-apr-8080-exec-55] (AbstractAuthenticationProcessingFilter.java:347) - Updated SecurityContextHolder to contain null Authentication
DEBUG [http-apr-8080-exec-55] (AbstractAuthenticationProcessingFilter.java:348) - Delegating to authentication failure handler loginsuccesshandler.AuthenticationFailureHandler@14883a3
DEBUG [http-apr-8080-exec-55] (DefaultRedirectStrategy.java:36) - Redirecting to '/SocialNetworking/utility/Login.jsf'
DEBUG [http-apr-8080-exec-55] (HttpSessionSecurityContextRepository.java:269) - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
DEBUG [http-apr-8080-exec-55] (SecurityContextPersistenceFilter.java:97) - SecurityContextHolder now cleared, as request processing completed
DEBUG [http-apr-8080-exec-49] (AntPathRequestMatcher.java:116) - Checking match of request : '/utility/login.jsf'; against '/utility/login.jsf*'
DEBUG [http-apr-8080-exec-49] (AntPathRequestMatcher.java:116) - Checking match of request : '/utility/login.jsf'; against '/utility/login.jsf*'
DEBUG [http-apr-8080-exec-49] (FilterChainProxy.java:180) - /utility/Login.jsf has an empty filter list
最後に
このビーンをあきらめて
application-context.xml
ファイルでは、ログインは成功しますが、サーバーコンソールで以下の情報を見ることができます。
DEBUG [http-apr-8080-exec-165] (HttpSessionSecurityContextRepository.java:139) - HttpSession returned null object for SPRING_SECURITY_CONTEXT
DEBUG [http-apr-8080-exec-165] (HttpSessionSecurityContextRepository.java:85) - No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@b910c1. A new one will be created.
解決方法は?
セキュリティの認証チェック部分で、認証されたオブジェクトを
SecurityContext
これは、リクエストがスプリングのセキュリティフィルタを通過したときに設定されます。私の推測では、ログイン直後はこれが設定されていません。おそらく、以下のようなハックを使って値を設定することができます。
try {
SecurityContext ctx = SecurityContextHolder.createEmptyContext();
SecurityContextHolder.setContext(ctx);
ctx.setAuthentication(event.getAuthentication());
//Do what ever you want to do
} finally {
SecurityContextHolder.clearContext();
}
更新してください。
また
InteractiveAuthenticationSuccessEvent
が呼び出されます。
SecurityContext
が設定される。
関連
-
[解決済み] SecurityContextにAuthenticationオブジェクトが見つかりませんでした - Spring 3.2.2
-
[解決済み] <mvc:default-servlet-handler />の必要性と用途は何ですか?
-
[解決済み] ApplicationContext(アノテーション付き)の読み込みに失敗しました。
-
FunctionService' タイプのビーンが見つかりませんでした。
-
[解決済み] org.hibernate.tool.schema.spi.CommandAcceptanceException: SpringBoot での h2 と JPA による JDBC 文での DDL 実行エラー
-
Springフレームワークを使用したアイデアで、コンテキストの初期化中に例外が発生し、リフレッシュの試みがキャンセルされる問題
-
[解決済み】Spring @Autowire プロパティとコンストラクタの違いについて
-
[解決済み】SpringのGA、RC、M2リリースの違いは何ですか?
-
[解決済み] Spring Expression Language (SpEL) と @Value: ドル vs. ハッシュ ($ vs. #)
-
[解決済み] Spring Frameworkにおける依存性注入と制御の逆転とは?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] Spring Hibernate - 現在のスレッドのトランザクション同期セッションを取得できませんでした。
-
[解決済み] spring-ws: エンドポイントマッピングが見つかりませんでした
-
SpringBootで'Application'を実行中にエラーが発生しました。コマンドラインが長すぎるため、コマンドラインを短くしてください。
-
レスポンスボディとレスポンスエンテイティ
-
[解決済み] WebApplicationContext が見つかりません: ContextLoaderListener が登録されていませんか?
-
[解決済み] Spring DataでOrderByをfindAllで使用する方法
-
[解決済み】Spring RestTemplateリクエストに "Accept: "ヘッダーを設定する方法は?
-
[解決済み】IntelliJから実行するときにSpring Bootプロファイルを有効にするにはどうすればよいですか?
-
[解決済み] Spring Resttemplateの例外処理
-
[解決済み] YAMLを使ったSpring @PropertySource