/* Copyright 2006-2009 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.codehaus.groovy.grails.plugins.springsecurity.facebook; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.codehaus.groovy.grails.plugins.springsecurity.SecurityRequestHolder; import org.springframework.security.Authentication; import org.springframework.security.AuthenticationException; import org.springframework.security.ui.AbstractProcessingFilter; import org.springframework.security.ui.FilterChainOrder; import org.springframework.security.ui.webapp.AuthenticationProcessingFilter; import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.w3c.dom.Document; import com.google.code.facebookapi.FacebookWebappHelper; /** * Intercepts j_spring_facebook_security_check to trigger Facebook login. * * @author Burt Beckwith */ public class FacebookAuthenticationProcessingFilter extends AbstractProcessingFilter { private String _apiKey; private String _secretKey; private String _authenticationUrlRoot; /** * {@inheritDoc} * @see org.springframework.security.ui.AbstractProcessingFilter#attemptAuthentication( * javax.servlet.http.HttpServletRequest) */ @Override public Authentication attemptAuthentication(final HttpServletRequest request) throws AuthenticationException { String authToken = request.getParameter("auth_token"); if (!StringUtils.hasText(authToken)) { // trigger a redirect to the Facebook login throw new FacebookAuthenticationRequiredException(); } FacebookAuthenticationToken token = createToken( authToken, request, SecurityRequestHolder.getResponse(), _apiKey, _secretKey); token.setDetails(authenticationDetailsSource.buildDetails(request)); Authentication authentication = getAuthenticationManager().authenticate(token); if (authentication.isAuthenticated()) { setLastUsername(token.getUserId(), request); } return authentication; } private void setLastUsername(final long userId, final HttpServletRequest request) { HttpSession session = request.getSession(false); if (session != null || getAllowSessionCreation()) { request.getSession().setAttribute( AuthenticationProcessingFilter.SPRING_SECURITY_LAST_USERNAME_KEY, String.valueOf(userId)); } } /** * Build an authentication from a login auth_token. * @param authToken the auth_token * @param request the http request * @param response the http response * @param apiKey the API key * @param secretKey the secret key * @return the auth token */ protected FacebookAuthenticationToken createToken( final String authToken, final HttpServletRequest request, final HttpServletResponse response, final String apiKey, final String secretKey) { try { FacebookWebappHelper helper = FacebookWebappHelper.newInstanceXml( request, response, apiKey, secretKey); if (helper.isLogin()) { String sessionKey = helper.doGetSession(authToken); return new FacebookAuthenticationToken(helper.getUser().longValue(), sessionKey); } return new FacebookAuthenticationToken(FacebookAuthenticationToken.Status.failure, null); } catch (RuntimeException e) { return new FacebookAuthenticationToken(FacebookAuthenticationToken.Status.error, e.getMessage()); } } /** * {@inheritDoc} * @see org.springframework.security.ui.AbstractProcessingFilter#determineFailureUrl( * javax.servlet.http.HttpServletRequest, org.springframework.security.AuthenticationException) */ @Override protected String determineFailureUrl(final HttpServletRequest request, final AuthenticationException failed) { if (failed instanceof FacebookAuthenticationRequiredException) { return _authenticationUrlRoot + _apiKey; } return super.determineFailureUrl(request, failed); } /** * {@inheritDoc} * @see org.springframework.security.ui.AbstractProcessingFilter#getDefaultFilterProcessesUrl() */ @Override public String getDefaultFilterProcessesUrl() { return "/j_spring_facebook_security_check"; } /** * {@inheritDoc} * @see org.springframework.security.ui.SpringSecurityFilter#getOrder() */ public int getOrder() { return FilterChainOrder.OPENID_PROCESSING_FILTER + 1; } /** * Dependency injection for the API key. * @param key the key */ public void setApiKey(final String key) { _apiKey = key; } /** * Dependency injection for the secret key. * @param key the key */ public void setSecretKey(final String key) { _secretKey = key; } /** * Dependency injection for the Facebook auth url root. * @param authenticationUrlRoot the url root */ public void setAuthenticationUrlRoot(String authenticationUrlRoot) { _authenticationUrlRoot = authenticationUrlRoot; } /** * {@inheritDoc} * @see org.springframework.security.ui.AbstractProcessingFilter#afterPropertiesSet() */ @Override public void afterPropertiesSet() throws Exception { super.afterPropertiesSet(); Assert.notNull(_apiKey, "API key must be specified"); Assert.notNull(_secretKey, "Secret key must be specified"); } }