100 bears for Ulrich!

It works. You made my day. Thanks,

-Borut

2009/1/23 Ulrich Stärk <u...@spielviel.de>

> Hi Borut,
>
> the problem was that both the OpenIdProcessingFilter and the filter used
> for form-based authentication both were configured for the same url, namely
> spring-security.check.url. Therefore both filters tried to process the
> credentials entered, which had to fail. I updated the wiki article.
> Basically it's all about introducing a new symbol,
> spring-security.openidcheck.url with the value
> "/j_spring_openid_security_check" and configuring the login page and the
> OpenId processing filter to use this instead of the
> spring-security.check.url. Then you can have to forms on your login page,
> one for openid login and the other for form-based logins and everything
> should work.
>
>
> Cheers,
>
> Uli
>
>
> Borut Bolčina schrieb:
>
>> Sure!
>>
>> 2008/12/12 Ulrich Stärk <u...@spielviel.de>
>>
>>  Please give me some time to have a look, atm I'm busy writing a paper for
>>> a
>>> conference in january.
>>>
>>> Cheers,
>>>
>>> Uli
>>>
>>> Borut Bolčina schrieb:
>>>
>>>  Hello Ulrich,
>>>
>>>> I hope you don't mind me writing you directly. I am trying to implement
>>>> OpenID and Username/Password authentication. I read your great article
>>>> at
>>>> T5
>>>> wiki.
>>>>
>>>> My goal: authenticate via DaoAuthenticationProvider if user inputs
>>>> username
>>>> and password OR authenticate via OpenIDAuthenticationProvider if user
>>>> enters
>>>> openid url.
>>>>
>>>> The problem: OpenIDAuthenticationProvider is trying to authenticate
>>>> eventhough it is contributed as second provider.
>>>>
>>>> Can you please have a look at the AppModule code and suggest a
>>>> correction?
>>>>
>>>> AppModule.java
>>>> ============
>>>> import java.io.IOException;
>>>>
>>>> import
>>>> nu.localhost.tapestry5.springsecurity.services.SpringSecurityServices;
>>>> import
>>>>
>>>>
>>>> nu.localhost.tapestry5.springsecurity.services.internal.HttpServletRequestFilterWrapper;
>>>>
>>>> import org.apache.tapestry5.SymbolConstants;
>>>> import org.apache.tapestry5.ioc.MappedConfiguration;
>>>> import org.apache.tapestry5.ioc.OrderedConfiguration;
>>>> import org.apache.tapestry5.ioc.ServiceBinder;
>>>> import org.apache.tapestry5.ioc.annotations.Inject;
>>>> import org.apache.tapestry5.ioc.annotations.InjectService;
>>>> import org.apache.tapestry5.ioc.annotations.Local;
>>>> import org.apache.tapestry5.ioc.annotations.Value;
>>>> import org.apache.tapestry5.services.HttpServletRequestFilter;
>>>> import org.apache.tapestry5.services.Request;
>>>> import org.apache.tapestry5.services.RequestFilter;
>>>> import org.apache.tapestry5.services.RequestHandler;
>>>> import org.apache.tapestry5.services.Response;
>>>> import org.slf4j.Logger;
>>>> import org.springframework.security.AuthenticationManager;
>>>> import org.springframework.security.providers.AuthenticationProvider;
>>>> import org.springframework.security.providers.dao.SaltSource;
>>>> import org.springframework.security.providers.encoding.PasswordEncoder;
>>>> import
>>>>
>>>>
>>>> org.springframework.security.providers.openid.OpenIDAuthenticationProvider;
>>>> import
>>>>
>>>>
>>>> org.springframework.security.ui.openid.OpenIDAuthenticationProcessingFilter;
>>>> import org.springframework.security.ui.rememberme.RememberMeServices;
>>>> import org.springframework.security.userdetails.UserDetailsService;
>>>>
>>>> /**
>>>>  * This module is automatically included as part of the Tapestry IoC
>>>> Registry, it's a good place to configure and extend
>>>>  * Tapestry, or to place your own service definitions.
>>>>  */
>>>> public class AppModule {
>>>>   public static void bind(ServiceBinder binder) {
>>>>       binder.bind(PersistenceManager.class,
>>>> PersistenceManagerImpl.class);
>>>>   }
>>>>
>>>>   public static void
>>>> contributeApplicationDefaults(MappedConfiguration<String, String>
>>>> configuration) {
>>>>       configuration.add(SymbolConstants.SUPPORTED_LOCALES,
>>>> "sl_SI,sr,en");
>>>>
>>>>       // The factory default is true but during the early stages of an
>>>> application
>>>>       // overriding to false is a good idea. In addition, this is often
>>>> overridden
>>>>       // on the command line as -Dtapestry.production-mode=false
>>>>       configuration.add(SymbolConstants.PRODUCTION_MODE, "false");
>>>>       configuration.add(SymbolConstants.COMPRESS_WHITESPACE, "false");
>>>>
>>>>       configuration.add("spring-security.failure.url", "/login/failed");
>>>>       // configuration.add( "spring-security.accessDenied.url",
>>>> "/forbidden" );
>>>>       // configuration.add(
>>>>       // "spring-security.check.url",
>>>>       // "/j_spring_security_check" );
>>>>       configuration.add("spring-security.target.url", "/index");
>>>>       // configuration.add( "spring-security.afterlogout.url", "/" );
>>>>       // configuration.add( "spring-security.rememberme.key",
>>>> "REMEMBERMEKEY" );
>>>>       configuration.add("spring-security.loginform.url", "/login");
>>>>       // configuration.add( "spring-security.force.ssl.login", "false"
>>>> );
>>>>       // configuration.add( "spring-security.anonymous.key",
>>>> "acegi_anonymous" );
>>>>       // configuration.add(
>>>>       // "spring-security.anonymous.attribute",
>>>>       // "anonymous,ROLE_ANONYMOUS" );
>>>>       configuration.add( "spring-security.password.salt", "DEADBEEF" );
>>>>   }
>>>>
>>>>   /**
>>>>    * This is a service definition, the service will be named
>>>> "TimingFilter". The interface, RequestFilter, is used
>>>>    * within the RequestHandler service pipeline, which is built from the
>>>> RequestHandler service configuration.
>>>>    * Tapestry IoC is responsible for passing in an appropriate Logger
>>>> instance. Requests for static resources are
>>>>    * handled at a higher level, so this filter will only be invoked for
>>>> Tapestry related requests.
>>>>    *
>>>>    * <p>
>>>>    * Service builder methods are useful when the implementation is
>>>> inline
>>>> as an inner class (as here) or require some
>>>>    * other kind of special initialization. In most cases, use the static
>>>> bind() method instead.
>>>>    *
>>>>    * <p>
>>>>    * If this method was named "build", then the service id would be
>>>> taken
>>>> from the service interface and would be
>>>>    * "RequestFilter". Since Tapestry already defines a service named
>>>> "RequestFilter" we use an explicit service id
>>>>    * that we can reference inside the contribution method.
>>>>    */
>>>>   public RequestFilter buildTimingFilter(final Logger log) {
>>>>       return new RequestFilter() {
>>>>           public boolean service(Request request, Response response,
>>>> RequestHandler handler) throws IOException {
>>>>               long startTime = System.currentTimeMillis();
>>>>
>>>>               try {
>>>>                   // The responsibility of a filter is to invoke the
>>>> corresponding method
>>>>                   // in the handler. When you chain multiple filters
>>>> together, each filter
>>>>                   // received a handler that is a bridge to the next
>>>> filter.
>>>>
>>>>                   return handler.service(request, response);
>>>>               } finally {
>>>>                   long elapsed = System.currentTimeMillis() - startTime;
>>>>
>>>>                   log.info(String.format("Request time: %d ms",
>>>> elapsed));
>>>>               }
>>>>           }
>>>>       };
>>>>   }
>>>>
>>>>   /**
>>>>    * This is a contribution to the RequestHandler service configuration.
>>>> This is how we extend Tapestry using the
>>>>    * timing filter. A common use for this kind of filter is transaction
>>>> management or security. The @Local annotation
>>>>    * selects the desired service by type, but only from the same module.
>>>> Without @Local, there would be an error due
>>>>    * to the other service(s) that implement RequestFilter (defined in
>>>> other modules).
>>>>    */
>>>>   public void
>>>> contributeRequestHandler(OrderedConfiguration<RequestFilter>
>>>> configuration, @Local RequestFilter filter) {
>>>>       // Each contribution to an ordered configuration has a name, When
>>>> necessary, you may
>>>>       // set constraints to precisely control the invocation order of
>>>> the
>>>> contributed filter
>>>>       // within the pipeline.
>>>>
>>>>       configuration.add("Timing", filter);
>>>>   }
>>>>
>>>>   /* COMMON UserDetailsService */
>>>>   public static UserDetailsService buildUserDetailsService(@Inject
>>>> PersistenceManager persistenceManager, final Logger log) {
>>>>       return new UserDetailsServiceImpl(persistenceManager,log);
>>>>   }
>>>>
>>>>   /* USERNAME, PASSWORD */
>>>> //    public static UserDetailsService
>>>> buildUserDetailsWithUsernameAndPasswordService(/*...@inject PasswordEncoder
>>>> encoder,
>>>> //            @Inject SaltSource salt, */final Logger log) {
>>>> //        return new
>>>> UserDetailsWithUsernameAndPasswordService(/*encoder,
>>>> salt, */log);
>>>> //    }
>>>>
>>>>   /* OPENID */
>>>> //    public static UserDetailsService
>>>> buildUserDetailsWithOpenIDService()
>>>> {
>>>> //        return new UserDetailsWithOpenIDServiceImpl();
>>>> //    }
>>>>
>>>>   public static OpenIDAuthenticationProvider
>>>> buildOpenIDAuthenticationProvider(
>>>>           @InjectService("UserDetailsWithOpenIDService")
>>>> UserDetailsService userDetailsService) throws Exception {
>>>>       OpenIDAuthenticationProvider provider = new
>>>> OpenIDAuthenticationProvider();
>>>>
>>>>       provider.setUserDetailsService(userDetailsService);
>>>>       provider.afterPropertiesSet();
>>>>
>>>>       return provider;
>>>>   }
>>>>
>>>>   public static void
>>>> contributeProviderManager(OrderedConfiguration<AuthenticationProvider>
>>>> configuration,
>>>>
>>>>           @InjectService("DaoAuthenticationProvider")
>>>> AuthenticationProvider daoAuthenticationProvider,
>>>>           @InjectService("OpenIDAuthenticationProvider")
>>>> AuthenticationProvider openIdAuthenticationProvider) {
>>>>
>>>>       configuration.add("daoAuthenticationProvider",
>>>> daoAuthenticationProvider);
>>>>       configuration.add("openIDAuthenticationProvider",
>>>> openIdAuthenticationProvider);
>>>>   }
>>>>
>>>>
>>>>   public static OpenIDAuthenticationProcessingFilter
>>>> buildRealOpenIDAuthenticationProcessingFilter(
>>>>           @SpringSecurityServices final AuthenticationManager manager,
>>>>           @SpringSecurityServices final RememberMeServices
>>>> rememberMeServices,
>>>>           @Inject @Value("${spring-security.check.url}") final String
>>>> authUrl,
>>>>           @Inject @Value("${spring-security.target.url}") final String
>>>> targetUrl,
>>>>           @Inject @Value("${spring-security.failure.url}") final String
>>>> failureUrl) throws Exception {
>>>>       OpenIDAuthenticationProcessingFilter filter = new
>>>> OpenIDAuthenticationProcessingFilter();
>>>>
>>>>       filter.setAuthenticationManager(manager);
>>>>       filter.setAuthenticationFailureUrl(failureUrl);
>>>>       filter.setDefaultTargetUrl(targetUrl);
>>>>       filter.setFilterProcessesUrl(authUrl);
>>>>       filter.setRememberMeServices(rememberMeServices);
>>>>       filter.afterPropertiesSet();
>>>>
>>>>       return filter;
>>>>   }
>>>>
>>>>   public static HttpServletRequestFilter
>>>> buildOpenIDAuthenticationProcessingFilter(
>>>>           final OpenIDAuthenticationProcessingFilter filter) {
>>>>       return new HttpServletRequestFilterWrapper(filter);
>>>>   }
>>>>
>>>>   public static void contributeHttpServletRequestHandler(
>>>>           OrderedConfiguration<HttpServletRequestFilter> configuration,
>>>>
>>>>           @InjectService("OpenIDAuthenticationProcessingFilter")
>>>> HttpServletRequestFilter openIDAuthenticationProcessingFilter) {
>>>>       configuration.add("openIDAuthenticationProcessingFilter",
>>>>
>>>>       openIDAuthenticationProcessingFilter,
>>>>
>>>>       "before:springSecurityAuthenticationProcessingFilter",
>>>>
>>>>       "after:springSecurityHttpSessionContextIntegrationFilter");
>>>>   }
>>>>
>>>> }
>>>>
>>>>
>>>>
>>>> Is there a problem in this last method
>>>> ("before:springSecurityAuthenticationProcessingFilter")? Both forms (for
>>>> u/p
>>>> and openid url) are on the same page.
>>>>
>>>> <html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd";>
>>>>   <head>
>>>>       <title>Najdi.si prijavna stran</title>
>>>>       <link rel="stylesheet" type="text/css"
>>>> href="${asset:context:css/iopenid.css}" />
>>>>   </head>
>>>>   <body>
>>>>       <t:layout xmlns:t="
>>>> http://tapestry.apache.org/schema/tapestry_5_0_0.xsd";>
>>>>
>>>>           <div style="margin-left: 50px">
>>>>               <t:block t:id="loginWithUserNameAndPassword">
>>>>                   <p>
>>>>                       Prijavite se z uporabniškim imenom in geslom ali z
>>>>                       <a t:type="actionlink" t:id="refreshOpenIDZone"
>>>> href="#" t:zone="loginZone">OpenID</a>
>>>>                   </p>
>>>>                   <form xmlns:t="
>>>> http://tapestry.apache.org/schema/tapestry_5_0_0.xsd";
>>>> action="${loginCheckUrl}" method="POST">
>>>>                       <t:if test="failed">
>>>>                           Napačno uporabniško ime ali geslo!
>>>>                           <br />
>>>>                       </t:if>
>>>>                       <label class="username"
>>>> for="j_username">uporabniško
>>>> ime:</label>
>>>>                       <input class="username" name="j_username"
>>>> type="text" size="10" maxlength="30" />
>>>>                       <label class="password"
>>>> for="j_password">geslo:</label>
>>>>                       <input class="password" name="j_password"
>>>> type="password" size="10" maxlength="30" />
>>>>                       <input id="submit" class="submit" type="submit"
>>>> value="log in" />
>>>>                   </form>
>>>>                   <p>Še nimate Najdi.si računa? <a t:type="pagelink"
>>>> t:page="Register" href="#">Registrirajte se!</a></p>
>>>>                   <p><a t:type="pagelink" t:page="RetrievePassword"
>>>> href="#">Pozabil sem geslo.</a></p>
>>>>               </t:block>
>>>>               <t:block t:id="loginWithOpenID">
>>>>                   <p>
>>>>                       Prijavite se z
>>>>                       <a t:type="actionlink"
>>>> t:id="refreshUsernamePasswordZone" href="#"
>>>> t:zone="loginZone">uporabniškim
>>>> imenom in
>>>>                           geslom</a>
>>>>                       ali z OpenID
>>>>                   </p>
>>>>                   <form xmlns:t="
>>>> http://tapestry.apache.org/schema/tapestry_5_0_0.xsd";
>>>> action="${loginCheckUrl}" method="POST">
>>>>                       <t:if test="failed">
>>>>                           Napaka!
>>>>                           <br />
>>>>                       </t:if>
>>>>                       <label class="username"
>>>> for="j_username">OpenID:</label>
>>>>                       <input class="username" name="j_username"
>>>> type="text" size="30" />
>>>>                       <input id="submit" class="submit" type="submit"
>>>> value="log in" />
>>>>                   </form>
>>>>                   <p>Še nimate Najdi.si računa? Ob <a t:type="pagelink"
>>>> t:page="Register" href="#">registraciji</a> dobite tudi Najdi.si
>>>> OpenID.</p>
>>>>               </t:block>
>>>>               <t:zone t:id="loginZone">
>>>>                   <t:delegate to="loginWithUserNameAndPassword" />
>>>>               </t:zone>
>>>>               <br />
>>>>
>>>>           </div>
>>>>
>>>>       </t:layout>
>>>>   </body>
>>>> </html>
>>>>
>>>>
>>>> public class Login {
>>>>   @Inject
>>>>   @Property
>>>>   private Block loginWithUserNameAndPassword;
>>>>
>>>>   @Inject
>>>>   @Property
>>>>   private Block loginWithOpenID;
>>>>
>>>>   @Inject
>>>>   @Property
>>>>   private Request _request;
>>>>
>>>>   void onActionFromRefreshPage() {
>>>>       // Nothing to do - the page will get fresh times as it is
>>>> rendered.
>>>>   }
>>>>
>>>>   Block onActionFromRefreshOpenIDZone() {
>>>>       // Check this is an AJAX link - if the link is clicked before the
>>>> DOM is fully loaded then AJAX behaviour won't
>>>>       // be there so don't try returning a Block. See
>>>> https://issues.apache.org/jira/browse/TAP5-1 .
>>>>       if (!_request.isXHR()) {
>>>>           return null;
>>>>       }
>>>>
>>>>       // Return the zone we want rendered. Without Ajax we'd typically
>>>> return the page we want rendered.
>>>>       return loginWithOpenID;
>>>>   }
>>>>
>>>>   Block onActionFromRefreshUsernamePasswordZone() {
>>>>       // Check this is an AJAX link - if the link is clicked before the
>>>> DOM is fully loaded then AJAX behaviour won't
>>>>       // be there so don't try returning a Block. See
>>>> https://issues.apache.org/jira/browse/TAP5-1 .
>>>>       if (!_request.isXHR()) {
>>>>           return null;
>>>>       }
>>>>
>>>>       // Return the zone we want rendered. Without Ajax we'd typically
>>>> return the page we want rendered.
>>>>       return loginWithUserNameAndPassword;
>>>>   }
>>>>
>>>>   @Inject
>>>>   @Value("${spring-security.check.url}")
>>>>   private String checkUrl;
>>>>
>>>>   @Inject
>>>>   private Request request;
>>>>
>>>>   private boolean failed = false;
>>>>
>>>>   public boolean isFailed() {
>>>>       return failed;
>>>>   }
>>>>
>>>>   public String getLoginCheckUrl() {
>>>>       return request.getContextPath() + checkUrl;
>>>>   }
>>>>
>>>>   void onActivate(String extra) {
>>>>       if (extra.equals("failed")) {
>>>>           failed = true;
>>>>       }
>>>>   }
>>>>
>>>> I would be really gratefull for your help!
>>>>
>>>> Regards,
>>>> Borut
>>>>
>>>>
>>>
>

Reply via email to