/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you 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.apache.shindig.social.core.oauth;

import com.google.inject.Inject;

import net.oauth.OAuthAccessor;
import net.oauth.OAuthConsumer;
import net.oauth.OAuthException;
import net.oauth.OAuthMessage;
import net.oauth.OAuthServiceProvider;
import net.oauth.SimpleOAuthValidator;
import net.oauth.server.OAuthServlet;
import org.apache.shindig.auth.AuthenticationHandler;
import org.apache.shindig.auth.SecurityToken;
import org.apache.shindig.social.opensocial.oauth.OAuthDataStore;
import org.apache.shindig.social.opensocial.oauth.OAuthEntry;

import java.io.IOException;
import java.net.URISyntaxException;
import javax.servlet.http.HttpServletRequest;

/**
 * Normal three legged OAuth handler
 */
public class OAuthAuthenticationHandler implements AuthenticationHandler {
  private static String AUTH_OAUTH_REQUEST = "OAuth";
  private OAuthDataStore store;

  @Inject
  public OAuthAuthenticationHandler(OAuthDataStore store) {
    this.store = store;
  }

  public String getName() {
    return AUTH_OAUTH_REQUEST;
  }

  public String getWWWAuthenticateHeader(String realm) {
    return String.format("OAuth realm=\"%s\"", realm);
  }

  public SecurityToken getSecurityTokenFromRequest(HttpServletRequest request) {
    OAuthMessage message = OAuthServlet.getMessage(request, null);
    OAuthEntry entry;


    try {
      // no token available...
      if (message.getToken() == null) return null;

      entry = store.getEntry(message.getToken());
    } catch (IOException e) {
      return null;
    }

    if (!isValidOAuthRequest(message, entry)) {
      return null;
    }

    return new OAuthSecurityToken(entry.userId, entry.callbackUrl, entry.appId,
        entry.domain, entry.container);
  }

  private boolean isValidOAuthRequest(OAuthMessage message, OAuthEntry entry) {
    if (entry == null) 
      throw new InvalidAuthenticationException("access token not found.", null);
    if (entry.type != OAuthEntry.Type.ACCESS)
      throw new InvalidAuthenticationException("token is not an access token.", null);
    if (entry.isExpired())
      throw new InvalidAuthenticationException("access token has expired.", null);

    OAuthServiceProvider provider = new OAuthServiceProvider(null, null, null);
    OAuthAccessor accessor = new OAuthAccessor(new OAuthConsumer(null, entry.consumerKey,
        store.getConsumer(entry.consumerKey).consumerSecret, provider));

    accessor.tokenSecret = entry.tokenSecret;
    accessor.accessToken = entry.token;

    try {
      message.validateMessage(accessor, new SimpleOAuthValidator());
    } catch (OAuthException e) {
      throw new InvalidAuthenticationException(e.getMessage(), e);
    } catch (IOException e) {
      return false;
    } catch (URISyntaxException e) {
      return false;
    }

    return true;
  }
}

@@ -2119,17 +2119,16 @@
 entry;%0A%0A
-%0A
     try 
@@ -2142,29 +2142,44 @@
  // 
-no token available...
+We only return null if this request 
 %0A   
@@ -2225,16 +2225,47 @@
 rn null;
+%0A      // no token available...
 %0A%0A      
@@ -2368,287 +2368,8 @@
  %7D%0A%0A
-    if (!isValidOAuthRequest(message, entry)) %7B%0A      return null;%0A    %7D%0A%0A    return new OAuthSecurityToken(entry.userId, entry.callbackUrl, entry.appId,%0A        entry.domain, entry.container);%0A  %7D%0A%0A  private boolean isValidOAuthRequest(OAuthMessage message, OAuthEntry entry) %7B%0A
     
@@ -2386,17 +2386,16 @@
 == null)
- 
 %0A      t
@@ -3262,101 +3262,298 @@
     
-return false;%0A    %7D catch (URISyntaxException e) %7B%0A      return false;%0A    %7D%0A%0A    return true
+throw new InvalidAuthenticationException(e.getMessage(), e);%0A    %7D catch (URISyntaxException e) %7B%0A      throw new InvalidAuthenticationException(e.getMessage(), e);%0A    %7D%0A%0A    return new OAuthSecurityToken(entry.userId, entry.callbackUrl, entry.appId,%0A        entry.domain, entry.container)
 ;%0A  

throw 401s when we have invalid OAuth credentials instead of falling through