/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.intel.mtwilson.security.jersey;
import com.intel.dcsg.cpg.crypto.CryptographyException;
import com.intel.mtwilson.model.Md5Digest;
import com.intel.mtwilson.datatypes.Role;
import com.intel.mtwilson.security.core.HttpBasicUserFinder;
import java.io.UnsupportedEncodingException;
import java.util.Calendar;
import javax.ws.rs.core.MultivaluedMap;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author ssbangal
*/
public class HttpBasicRequestVerifier {
private static Logger log = LoggerFactory.getLogger(HttpBasicRequestVerifier.class);
private HttpBasicUserFinder finder;
public HttpBasicRequestVerifier(HttpBasicUserFinder finder) {
this.finder = finder;
}
public User getUserForRequest(String httpMethod, String requestUrl, MultivaluedMap<String, String> headers, String requestBody) throws CryptographyException {
String userName;
String userSpecifiedPassword;
String authorizationHeader = headers.getFirst("Authorization");
HttpBasicRequestVerifier.Authorization auth = parseAuthorization(authorizationHeader);
String realm = new String(Base64.decodeBase64(auth.realm));
//log.debug("VerifyAuthorization Header: Signed content (" + realm.length() + ") follows:\n" + realm);
// In HttpBasic, the user name and password would be separated by :
String[] loginInfo = realm.split(":");
// Here we need to handle the scenario where in the password might be empty
if (loginInfo.length == 0) {
throw new CryptographyException("Login credentials specified are not valid.");
}
if (loginInfo.length == 1) {
// Since the user has not specified the password, we will keep it blank. Some folks might want to use blank password.
userName = loginInfo[0];
userSpecifiedPassword = "";
} else {
userName = loginInfo[0];
userSpecifiedPassword = loginInfo[1];
}
log.debug("VerifyAuthorization: Username: " + userName);
String userPasswordInSystem = finder.getPasswordForUser(userName);
if (userPasswordInSystem == null) {
throw new CryptographyException("User specified is currently not configured in the system.");
}
log.info("VerifyAuthorization: Retrieved the user credentials from DB");
if (!userPasswordInSystem.equals(userSpecifiedPassword)) {
log.error("Request is NOT Authenticated");
throw new CryptographyException("Either the user name or password specified is not correct.");
}
String insecureRequestSummary = httpMethod+ " "+requestUrl + " "+String.valueOf(headers.getFirst("Date")); // the hash of this complete value will not be used in anti-replay protection, but it will be logged in the database with the request.
// Because of security reasons, the users using HttpBasic would be able to just retrieve the attestation status and will
// not have previleges for any any other operations.
try {
log.info("Request is authenticated");
User userInfo = new User(userName, new Role[]{Role.Report}, userName, Md5Digest.valueOf(insecureRequestSummary.getBytes("UTF-8")));
return userInfo;
}
catch(UnsupportedEncodingException e) {
// unlikely to happen because we are using UTF-8 ...
User userInfo = new User(userName, new Role[]{Role.Report}, userName, Md5Digest.valueOf(insecureRequestSummary.getBytes()));
return userInfo;
}
}
/**
* Below is a sample of the Authorization header that would be parsed. The base 64 encoded part is a combination of
* user name and password separated by : Example: Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
*
* @param authorizationHeader
* @return
*/
private Authorization parseAuthorization(String authorizationHeader) {
Authorization auth = new Authorization();
String[] terms = authorizationHeader.split(" ");
if (!"Basic".equals(terms[0])) {
throw new IllegalArgumentException("Authorization type is not Basic");
}
// Return back the base64 encoded user name and password
auth.realm = terms[1];
return auth;
}
public static class Authorization {
public String realm;
}
}