/*
* Copyright (C) 2008 Universidade Federal de Campina Grande
*
* This file is part of OurGrid.
*
* OurGrid is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.ourgrid.peer.business.controller.voms;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.Socket;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509KeyManager;
import javax.net.ssl.X509TrustManager;
import org.ourgrid.peer.business.controller.messages.VOMSMessages;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import sun.security.provider.certpath.X509CertPath;
import br.edu.ufcg.lsd.commune.network.signature.Util;
import com.sun.org.apache.xerces.internal.parsers.DOMParser;
/**
*
*/
public class VomsAuthorisationStrategy {
private static final String DN_XMLTAG = "DN";
private static final String SSL_PROTOCOL = "SSLv3";
private static final String VOMS_URL_PROT = "https://";
private static final String VOMS_SERVICE_URL = "/services/VOMSAdmin?method=listMembers";
private static final String COMMUNE_DN_SEPARATOR = ",";
private static final String VOMS_DN_SEPARATOR = "/";
private final X509CertPath myCertPath;
private final String myPrivateKey;
public VomsAuthorisationStrategy(X509CertPath myCertPath, String myPrivateKey) {
this.myCertPath = myCertPath;
this.myPrivateKey = myPrivateKey;
}
public VomsAuthorisationData authorise(String providerDN, List<String> vomsURLList) throws Exception {
if (vomsURLList.isEmpty()) {
return new VomsAuthorisationData(true, new ArrayList<String>());
}
List<String> allDNs = new ArrayList<String>();
boolean authorised = false;
for (String vomsURL : vomsURLList) {
List<String> providerDns = getAuthorisedDNList(vomsURL);
for (String vomsProviderDN : providerDns) {
allDNs.add(vomsProviderDN);
authorised |= dnEquals(providerDN, vomsProviderDN);
}
}
return new VomsAuthorisationData(authorised, allDNs);
}
public class VomsAuthorisationData {
private final boolean isAuthorised;
private final List<String> usersDN;
public VomsAuthorisationData(boolean isAuthorised, List<String> usersDN) {
this.isAuthorised = isAuthorised;
this.usersDN = usersDN;
}
/**
* @return the isAuthorised
*/
public boolean isAuthorised() {
return isAuthorised;
}
/**
* @return the usersDN
*/
public List<String> getUsersDN() {
return usersDN;
}
}
private List<String> getAuthorisedDNList(String vomsURL) throws Exception,
MalformedURLException, NoSuchAlgorithmException,
KeyManagementException, IOException, SAXException {
if (vomsURL == null) {
throw new Exception(VOMSMessages.getNullVOMSUrlMessage());
}
URL url = new URL(VOMS_URL_PROT + vomsURL + VOMS_SERVICE_URL);
HttpsURLConnection connection = setUpConnection(url);
InputStream inputStream = connection.getInputStream();
List<String> providerDns = parseXML(inputStream);
return providerDns;
}
public static boolean dnEquals(String providerDN, String vomsProviderDN) {
Set<String> providerDNSet = new LinkedHashSet<String>(
Arrays.asList(providerDN.split(COMMUNE_DN_SEPARATOR)));
Set<String> vomsProviderDNSet = new LinkedHashSet<String>(
Arrays.asList(vomsProviderDN.substring(1).split(VOMS_DN_SEPARATOR)));
return providerDNSet.equals(vomsProviderDNSet);
}
private List<String> parseXML(InputStream xMLStream) throws SAXException, IOException {
InputSource source = new InputSource(xMLStream);
DOMParser parser = new DOMParser();
parser.parse(source);
Document xMLDocument = parser.getDocument();
List<String> allDns = new LinkedList<String>();
NodeList dnNodes = xMLDocument.getElementsByTagName(DN_XMLTAG);
for (int i = 0; i < dnNodes.getLength(); i++) {
Node item = dnNodes.item(i);
allDns.add(item.getFirstChild().getNodeValue());
}
return allDns;
}
private HttpsURLConnection setUpConnection(URL url)
throws NoSuchAlgorithmException, KeyManagementException,
IOException {
HttpsURLConnection openConnection = (HttpsURLConnection) url.openConnection();
openConnection.setAllowUserInteraction(true);
openConnection.setUseCaches(false);
openConnection.setDoInput(true);
openConnection.setDoOutput(true);
SSLContext sc = SSLContext.getInstance(SSL_PROTOCOL);
sc.init(new KeyManager[]{new MyKeyManager()}, new TrustManager[]{new BypassTrustManager()}, null);
openConnection.setSSLSocketFactory(sc.getSocketFactory());
return openConnection;
}
private class MyKeyManager implements X509KeyManager {
private static final String CLIENT_ALIAS = "Client";
public String chooseClientAlias(String[] keyType, Principal[] issuers,
Socket socket) {
return CLIENT_ALIAS;
}
public String chooseServerAlias(String keyType, Principal[] issuers,
Socket socket) {
return null;
}
public X509Certificate[] getCertificateChain(String alias) {
return myCertPath.getCertificates().toArray(new X509Certificate[]{});
}
public String[] getClientAliases(String keyType, Principal[] issuers) {
return null;
}
public PrivateKey getPrivateKey(String alias) {
try {
return Util.decodePrivateKey(myPrivateKey);
} catch (InvalidKeySpecException e) {
return null;
}
}
public String[] getServerAliases(String keyType, Principal[] issuers) {
return null;
}
}
private class BypassTrustManager implements X509TrustManager {
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
}