/*
* Copyright 2011 PA Consulting Ltd
*
* 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 com.prodeagle.java;
import java.io.IOException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.logging.Logger;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.appengine.api.NamespaceManager;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.memcache.MemcacheService;
import com.google.appengine.api.memcache.MemcacheServiceFactory;
import com.google.appengine.api.urlfetch.HTTPResponse;
import com.google.appengine.api.urlfetch.URLFetchService;
import com.google.appengine.api.urlfetch.URLFetchServiceFactory;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
public class Authentication {
private static final Logger _logger = Logger.getLogger(Authentication.class.getSimpleName());
private static final String NAMESPACE = "prodeagle";
private static final String SECURE_HOST = "https://prod-eagle.appspot.com";
public static String getKeySecret(HttpServletRequest req, HttpServletResponse resp) {
return getKeySecret(req, resp, null);
}
public static String getKeySecret(HttpServletRequest req, HttpServletResponse resp, String updateAuth) {
String originalNamespace = NamespaceManager.get();
NamespaceManager.set(NAMESPACE);
try { //put in a try so that we can have a finally block which resets namespaces
Key key = KeyFactory.createKey("AuthKey", "master");
DatastoreService datastoreService = DatastoreServiceFactory.getDatastoreService();
MemcacheService memcacheService = MemcacheServiceFactory.getMemcacheService();
// look for the auth key in the datastore
Entity authEntity = (Entity) memcacheService.get(KeyFactory.keyToString(key));
if (authEntity == null) {
try {
authEntity = datastoreService.get(key);
memcacheService.put(KeyFactory.keyToString(key), authEntity);
} catch (EntityNotFoundException e) {
_logger.info("Authentication entity not found in memcache or datastore");
authEntity = null;
}
}
if (null != updateAuth) {
//if we're updating the auth
if (null == authEntity || !authEntity.getProperty("secret").equals(updateAuth)) {
//if there is no auth key, or the auth key doesn't match the one provided
try {
URLFetchService fetchService = URLFetchServiceFactory.getURLFetchService();
String host = URLEncoder.encode(req.getHeader("Host"), "UTF-8");
HTTPResponse response = fetchService.fetch(new URL(SECURE_HOST + "/auth/?site=" + host + "&auth=" + updateAuth));
if (response.getResponseCode() == 200) {
//if successfully received a response, save the new auth key
String content = new String(response.getContent());
if (content.equals(new String("OK"))) {
authEntity = new Entity(key);
authEntity.setProperty("secret", updateAuth);
datastoreService.put(authEntity);
memcacheService.put(KeyFactory.keyToString(key), authEntity);
}
}
} catch (Exception e) {
_logger.severe("Exception while updating key: " + e);
return null;
}
}
}
if (null != authEntity) {
//if the key did match or we've since updated it, return it
return (String) authEntity.getProperty("secret");
} else {
//otherwise return nothing
return null;
}
} finally {
//always reset the namespace
NamespaceManager.set(originalNamespace);
}
}
public static Boolean isProdEagle(HttpServletRequest req, HttpServletResponse resp) {
String possibleAuth = req.getParameter("auth");
if (null != possibleAuth) {
String secret = getKeySecret(req, resp, possibleAuth);
if (null != secret && secret.equals(possibleAuth)) {
return true;
}
}
return false;
}
public static Boolean isAdministrator(HttpServletRequest req, HttpServletResponse resp) {
UserService userService = UserServiceFactory.getUserService();
User user = userService.getCurrentUser();
try {
if (null == user) {
String loginUrl = userService.createLoginURL(req.getRequestURI() + "?" + req.getQueryString());
_logger.info("Sending redirect to: " + loginUrl);
resp.sendRedirect(loginUrl);
return false;
} else if (userService.isUserAdmin()) {
return true;
} else {
_logger.info("User is logged in, but not an admin");
resp.getWriter().print(String.format(
"Please login with an administrator account. <a href=\"%s\">Logout</a>",
userService.createLogoutURL(req.getRequestURI() + "?" + req.getQueryString())));
}
} catch (IOException e) {
_logger.severe("Failure to write logout info. Exception: " + e);
}
return false;
}
public static void addUser(HttpServletRequest req, HttpServletResponse resp) {
if (isAdministrator(req, resp)) {
_logger.info("User is an admin. Getting secret");
String secret = getKeySecret(req, resp);
try {
if (null == secret) {
resp.getWriter().print("ProdEagle hasn't set your secret yet. Please visit prodeagle.com and register your website.");
return;
} else {
String type = "administrator";
String email = req.getParameter("administrator");
if (null != req.getParameter("viewer")) {
type = "viewer";
email = req.getParameter("viewer");
}
String host = URLEncoder.encode(req.getHeader("Host"), "UTF-8");
resp.sendRedirect(SECURE_HOST + "/auth/?site=" + host + "&auth=" + secret + "&" + type + "=" + email);
}
} catch (IOException e) {
_logger.severe("Failure to write response for adding a user. Exception: " + e);
}
} else {
_logger.info("User is not an admin. Cannot add user");
}
}
}