diff options
Diffstat (limited to 'base/console/src/com/netscape/admin/certsrv/connection')
10 files changed, 2358 insertions, 0 deletions
diff --git a/base/console/src/com/netscape/admin/certsrv/connection/AdminConnection.java b/base/console/src/com/netscape/admin/certsrv/connection/AdminConnection.java new file mode 100644 index 000000000..acb023132 --- /dev/null +++ b/base/console/src/com/netscape/admin/certsrv/connection/AdminConnection.java @@ -0,0 +1,818 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.admin.certsrv.connection; + +import java.io.*; +import java.net.*; +import java.util.*; + +import com.netscape.certsrv.common.*; +import com.netscape.admin.certsrv.*; +import com.netscape.management.client.util.*; +import com.netscape.management.client.*; +import com.netscape.management.client.preferences.*; + +/** + * This class represents an administration connection shell + * to the certificate server. The user need to specify the + * connection factory + * + * @author thomask + * @author Jack Pan-Chen + * @version $Revision$, $Date$ + * @see com.netscape.certsrv.client.connection + * @see com.netscape.certsrv.client + */ +public class AdminConnection { + + /*========================================================== + * variables + *==========================================================*/ + public static int NO_TIMEOUT = 0; + public static int DEFAULT_TIMEOUT = 600000; //600 sec + + private IConnectionFactory mFactory= null; + private IConnection mConn = null; + private IAuthenticator mAuth = null; + private int mDefaultTimeout = DEFAULT_TIMEOUT; + private int mCurrentTimeout = DEFAULT_TIMEOUT; + private boolean mIsKeepAlive = false; + private String mHost; + private int mPort; + private IConnectionListener mConnectionListener; + private String mAuthType=""; + private String mPath=null; + private static FilePreferenceManager mPM = null; + + /*========================================================== + * constructors + *==========================================================*/ + + /** + * Default Constructor<p> + * Construct an administartion connection with keep alive disabled + * + * @param auth authentication mechanism object + * @param factory factory used to create server connection + * @param host server host name + * @param port server port number + * + * @see com.netscape.certsrv.client.connection.IConnection + * @see com.netscape.certsrv.client.connection.IConnectionFactory + * @see com.netscape.certsrv.client.connection.IAuthenticator + */ + public AdminConnection( IAuthenticator auth, + IConnectionFactory factory, + String host, int port, String path) { + if (mPM == null) { + mPM = new FilePreferenceManager(Framework.IDENTIFIER, + Framework.VERSION); + } + Preferences p = mPM.getPreferences( + Framework.PREFERENCES_GENERAL); + int timeout = p.getInt("CMSConnTimeout", 600000); + setDefaultTimeout(timeout); + setCurrentTimeout(timeout); + Debug.println("AdminConnection: " + timeout + " " + + mPM.getClass().getName()); + + mAuth = auth; + mFactory = factory; + mHost = host; + mPort = port; + mPath = path; + } + + /** + * Default Constructor<p> + * Construct an administartion connection + * + * @param auth authentication mechanism object + * @param factory factory used to create server connection + * @param enableKeepAlive enable HTTP keep alive or not + * @param host server host name + * @param port server port number + * + * @see com.netscape.certsrv.client.connection.IConnection + * @see com.netscape.certsrv.client.connection.IConnectionFactory + * @see com.netscape.certsrv.client.connection.IAuthenticator + */ + public AdminConnection( IAuthenticator auth, + IConnectionFactory factory, + boolean enableKeepAlive, + String host, int port, String path) { + if (mPM == null) { + mPM = new FilePreferenceManager(Framework.IDENTIFIER, + Framework.VERSION); + } + Preferences p = mPM.getPreferences( + Framework.PREFERENCES_GENERAL); + int timeout = p.getInt("CMSConnTimeout", 600000); + setDefaultTimeout(timeout); + setCurrentTimeout(timeout); + Debug.println("AdminConnection: " + timeout + " " + + mPM.getClass().getName()); + + mAuth = auth; + mFactory = factory; + mIsKeepAlive = enableKeepAlive; + mHost = host; + mPort = port; + mPath = path; + } + + /*========================================================== + * private methods + *==========================================================*/ + + private String b64encode (byte[] data) { + int i, k, n; + int len = data.length; + byte b; + StringBuffer b64 = new StringBuffer(); + String base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + for (i = 0; i < len; i += 3) { + byte d0 = data[i]; + byte d1 = (i+1<len)? data[i+1]: (byte)0; + byte d2 = (i+2<len)? data[i+2]: (byte)0; + b = (byte)((d0 & (byte)0xFC) >>> 2); + b64.append(base64.charAt((int)b)); + b = (byte)(((d0 & 0x03) << 4) | ((d1 & 0xF0) >>> 4)); + b64.append(base64.charAt((int)b)); + b = (byte)(((d1 & 0x0F) << 2) | ((d2 & 0xC0) >>> 6)); + if (i+1 < len) { + b64.append(base64.charAt((int)b)); + } else { + b64.append('='); + } + b = (byte)(d2 & 0x3F); + if (i+2 < len) { + b64.append(base64.charAt((int)b)); + } else { + b64.append('='); + } + } + + b64.append('\n'); + + return b64.toString(); + } + + /*========================================================== + * public methods + *==========================================================*/ + + /** + * Set the listener. + */ + public void setConnectionListener(IConnectionListener l) { + mConnectionListener = l; + } + + /** + * Returns the authentication object for this connection.<p> + * The choice of authentication object is dependding on the + * authentication method used on the server side. + * + * @return authentication object + * @see com.netscape.certsrv.client.connection.IAuthenticator + * @see com.netscape.certsrv.client.connection.BasicAuthenticator + */ + public IAuthenticator getAuthenticator() { + return mAuth; + } + + /** + * Returns the connection object used to establish the connection + * This can be SSLavaConnection or SSLConnection. THIS OBJECT REFERENCE + * IS NOT STABLE, SINCE IT IS RECREATED EACH TIME IF KEEPALIVE IS NOT + * ENABLE. + * + * @return connection object + */ + public IConnection getIConnection() { + return mConn; + } + + /** + * Sets the one time current timeout value for specific operation + * if less then default timeout the default timeout is used. + * + * @param timeout time in ms + */ + public void setCurrentTimeout(int timeout) { + mCurrentTimeout = timeout; + } + + + /** + * Sets the default timeout value + * @param timeout time in ms + */ + public void setDefaultTimeout(int timeout) { + mDefaultTimeout = timeout; + } + + /** + * OPERATION: ADD<p> + * + * <pre> + * FORMAT: + * + * GET/[OP_DEST]? + * OP_TYPE=[OP_TYPE]& + * OP_SCOPE=[OP_SCOPE]& + * RS_ID=[RS_ID]& + * [NAME=VALUE][&[NAME=VALUE]] + * + * </pre> + * + * Add new entries into the scope using the NVP information provided. + * This operation will ONLY be used by DYNAMIC content and + * configuartion, such as Users and Groups, and Policies. + * + * @param dest OP_DEST + * @param scope OP_SCOPE + * @param id RS_ID + * @param pairs NVP info + * + * @see http://warp/server/certificate/columbo/design/ui/admin-protocol-definition.html + * + */ + public void add(String dest, String scope, String id, NameValuePairs pairs) + throws EAdminException { + + checkParams(dest,scope,id,pairs); + Request request = new Request(mPath + "/" + dest); + request.set(Constants.OP_TYPE, OpDef.OP_ADD); + request.set(Constants.OP_SCOPE, scope); + request.set(Constants.RS_ID, id); + for (String name : pairs.keySet()) { + String value = pairs.get(name); + request.set(name, value); + } + Response response = sendRequest(request); + if (response.getReturnCode() == Response.SUCCESS) { + return; + } + throw new EAdminException(response.getErrorMessage(), true); + } + + /** + * OPERATION: DELETE<p> + * + * <pre> + * FORMAT: + * + * GET/[OP_DEST]? + * OP_TYPE=[OP_TYPE]& + * OP_SCOPE=[OP_SCOPE]& + * RS_ID=[RS_ID]& + * + * </pre> + * + * Removing an entry with specified id from the scope specified. + * + * @param dest OP_DEST + * @param scope OP_SCOPE + * @param id RS_ID + * + * @see http://warp/server/certificate/columbo/design/ui/admin-protocol-definition.html + * + */ + public void delete(String dest, String scope, String id) + throws EAdminException { + + checkParams(dest,scope,id); + Request request = new Request(mPath + "/" + dest); + request.set(Constants.OP_TYPE, OpDef.OP_DELETE); + request.set(Constants.OP_SCOPE, scope); + request.set(Constants.RS_ID, id); + Response response = sendRequest(request); + if (response.getReturnCode() == Response.SUCCESS) { + return; + } + throw new EAdminException(response.getErrorMessage(), true); + } + + public void delete(String dest, String scope, String id, NameValuePairs pairs) + throws EAdminException { + + checkParams(dest,scope,id,pairs); + Request request = new Request(mPath + "/" + dest); + request.set(Constants.OP_TYPE, OpDef.OP_DELETE); + request.set(Constants.OP_SCOPE, scope); + request.set(Constants.RS_ID, id); + for (String name : pairs.keySet()) { + String value = pairs.get(name); + request.set(name, value); + } + Response response = sendRequest(request); + if (response.getReturnCode() == Response.SUCCESS) { + return; + } + throw new EAdminException(response.getErrorMessage(), true); + } + + /** + * OPERATION: AUTH<p> + * + * <pre> + * FORMAT: + * + * GET/[OP_DEST]? + * OP_TYPE=[OP_TYPE]& + * OP_SCOPE=[OP_SCOPE]& + * [NAME=VALUE][&[NAME=VALUE]] + * + * </pre> + * + * getting properties (name-value pairs) using some criteria + * specified in NVP. + * + * @param dest OP_DEST + * @param scope OP_SCOPE + * @param pairs NVP search filter + * + * @see http://warp/server/certificate/columbo/design/ui/admin-protocol-definition.html + * + */ + public void auth(String dest, String scope) throws EAdminException { + Request request = new Request(mPath + "/" + dest); + request.set(Constants.OP_TYPE, OpDef.OP_AUTH); + request.set(Constants.OP_SCOPE, scope); + Response response = sendRequest(request); + if (response.getReturnCode() == Response.SUCCESS) { + return; + } + throw new EAdminException(response.getErrorMessage(), true); + } + + public String authType(String dest, String scope) throws EAdminException { + Request request = new Request(mPath + "/" + dest); + request.set(Constants.OP_TYPE, OpDef.OP_AUTH); + request.set(Constants.OP_SCOPE, scope); + + Response response = sendRequest(request); + if (response.getReturnCode() == Response.SUCCESS) { + Enumeration e = response.getNames(); + while (e.hasMoreElements()) { + String n = (String)e.nextElement(); + if (n.equals("authType")) + mAuthType = response.get(n); + return mAuthType; + } + return ""; + } + throw new EAdminException(response.getErrorMessage(), true); + } + + /** + * OPERATION: SEARCH<p> + * + * <pre> + * FORMAT: + * + * GET/[OP_DEST]? + * OP_TYPE=[OP_TYPE]& + * OP_SCOPE=[OP_SCOPE]& + * [NAME=VALUE][&[NAME=VALUE]] + * + * </pre> + * + * getting properties (name-value pairs) using some criteria + * specified in NVP. + * + * @param dest OP_DEST + * @param scope OP_SCOPE + * @param pairs NVP search filter + * + * @see http://warp/server/certificate/columbo/design/ui/admin-protocol-definition.html + * + */ + public NameValuePairs search(String dest, String scope, NameValuePairs filters) + throws EAdminException { + + checkParams(dest,scope,"",filters); + Request request = new Request(mPath + "/" + dest); + request.set(Constants.OP_TYPE, OpDef.OP_SEARCH); + request.set(Constants.OP_SCOPE, scope); + for (String name : filters.keySet()) { + String value = filters.get(name); + request.set(name, value); + } + + Response response = sendRequest(request); + + if (response.getReturnCode() == Response.SUCCESS) { + NameValuePairs newpairs = new NameValuePairs(); + Enumeration e = response.getNames(); + while (e.hasMoreElements()) { + String n = (String)e.nextElement(); + newpairs.put(n, response.get(n)); + } + return newpairs; + } + throw new EAdminException(response.getErrorMessage(), true); + } + + /** + * OPERATION: READ<p> + * + * <pre> + * FORMAT: + * + * GET/[OP_DEST]? + * OP_TYPE=[OP_TYPE]& + * OP_SCOPE=[OP_SCOPE]& + * RS_ID=[RS_ID]& + * [NAME=VALUE][&[NAME=VALUE]] + * + * </pre> + * + * getting specific properties (name-value pairs) using + * attributes specified in NVP. + * + * @param dest OP_DEST + * @param scope OP_SCOPE + * @param id RS_ID + * @param pairs NVP info + * + * @see http://warp/server/certificate/columbo/design/ui/admin-protocol-definition.html + * + */ + public NameValuePairs read(String dest, String scope, String id, NameValuePairs pairs) + throws EAdminException { + + checkParams(dest,scope,id); + Request request = new Request(mPath + "/" + dest); + request.set(Constants.OP_TYPE, OpDef.OP_READ); + request.set(Constants.OP_SCOPE, scope); + request.set(Constants.RS_ID, id); + for (String name : pairs.keySet()) { + String value = pairs.get(name); + request.set(name, value); + } + + Response response = sendRequest(request); + + if (response.getReturnCode() == Response.SUCCESS) { + NameValuePairs newpairs = new NameValuePairs(); + Enumeration e = response.getNames(); + while (e.hasMoreElements()) { + String n = (String)e.nextElement(); + newpairs.put(n, response.get(n)); + } + return newpairs; + } + throw new EAdminException(response.getErrorMessage(), true); + } + + public NameValuePairs process(String dest, String scope, String id, + NameValuePairs pairs) throws EAdminException { + return process(dest, scope, id, pairs, false); + } + + public NameValuePairs process(String dest, String scope, String id, + NameValuePairs pairs, boolean useGET) throws EAdminException { + Request request = new Request(mPath + "/" + dest); + request.set(Constants.OP_TYPE, OpDef.OP_PROCESS); + request.set(Constants.OP_SCOPE, scope); + request.set(Constants.RS_ID, id); + + for (String name : pairs.keySet()) { + String value = pairs.get(name); + request.set(name, value); + } + + Response response = sendRequest(request, useGET); + if (response.getReturnCode() == Response.SUCCESS) { + NameValuePairs newpairs = new NameValuePairs(); + Enumeration e = response.getNames(); + while (e.hasMoreElements()) { + String n = (String)e.nextElement(); + newpairs.put(n, response.get(n)); + } + return newpairs; + } + throw new EAdminException(response.getErrorMessage(), true); + } + + public void validate(String dest, String scope, NameValuePairs pairs) + throws EAdminException { + Request request = new Request(mPath + "/" + dest); + request.set(Constants.OP_TYPE, OpDef.OP_VALIDATE); + request.set(Constants.OP_SCOPE, scope); + for (String name : pairs.keySet()) { + String value = pairs.get(name); + request.set(name, value); + } + + Response response = sendRequest(request); + if (response.getReturnCode() == Response.SUCCESS) { + return; + } + throw new EAdminException(response.getErrorMessage(), true); + } + + /** + * OPERATION: MODIFY<p> + * + * <pre> + * FORMAT: + * + * GET/[OP_DEST]? + * OP_TYPE=[OP_TYPE]& + * OP_SCOPE=[OP_SCOPE]& + * RS_ID=[RS_ID]& + * [NAME=VALUE][&[NAME=VALUE]] + * + * </pre> + * + * Modify an existing entry's attributes. + * + * @param dest OP_DEST + * @param scope OP_SCOPE + * @param id RS_ID + * @param pairs NVP info + * + * @see http://warp/server/certificate/columbo/design/ui/admin-protocol-definition.html + * + */ + public void modify(String dest, String scope, String id, NameValuePairs pairs) + throws EAdminException { + modify(dest, scope, id, pairs, false); + } + + public void modify(String dest, String scope, String id, NameValuePairs pairs, boolean useGET) + throws EAdminException { + + checkParams(dest,scope,id,pairs); + Request request = new Request(mPath + "/" + dest); + request.set(Constants.OP_TYPE, OpDef.OP_MODIFY); + request.set(Constants.OP_SCOPE, scope); + request.set(Constants.RS_ID, id); + for (String name : pairs.keySet()) { + String value = pairs.get(name); + request.set(name, value); + } + Response response = sendRequest(request, useGET); + if (response.getReturnCode() == Response.SUCCESS) { + return; + } else if (response.getReturnCode() == Response.RESTART) { + mConnectionListener.restartCallback(); + return; + } + throw new EAdminException(response.getErrorMessage(), true); + } + + private synchronized void retryConnection() throws EAdminException { + if (mConn instanceof JSSConnection) { + JSSConnection conn = (JSSConnection)mConn; + if (!conn.isTokenPasswordInit()) { + mConn = null; + if (!conn.isSamePwd()) { + throw new EAdminException(CMSAdminResources.SERVERCONNECTION_DIFFERENT_PWD, false); + } + throw new EAdminException(CMSAdminResources.SERVERCONNECTION_TOKEN_INIT_FAILED, false); + } + + if (!conn.isServerCertImported()) { + mConn = null; + throw new EAdminException(CMSAdminResources.SERVERCONNECTION_SERVER_CERT_IMPORTED_FAILED, false); + } + if (!conn.isCertAccepted()) { + mConn = null; + throw new EAdminException(CMSAdminResources.SERVERCONNECTION_SERVER_CERT_DENIED, false); + } + if (conn != null && conn.isAbortAction() && conn.isClientAuth()) { + mConn = null; + throw new EAdminException(CMSAdminResources.SERVERCONNECTION_NO_CLIENT_CERT, false); + } + if (conn != null && !conn.hasClientCert()) { + mConn = null; + throw new EAdminException(CMSAdminResources.SERVERCONNECTION_NO_CLIENT_CERT, false); + } + } + try { + mConn = mFactory.create(mHost, mPort); + } catch (UnknownHostException e) { + mConn = null; + throw new EAdminException(CMSAdminResources.UNKNOWNHOST, false); + } catch (IOException e) { + mConn = null; + throw new EAdminException(CMSAdminResources.SERVER_UNREACHABLE, false); + } catch (Exception e) { + mConn = null; + if (Debug.isEnabled()) { + e.printStackTrace(); + } + throw new EAdminException(CMSAdminResources.UNKNOWNEXCEPTION, false); + } + } + + /** + * Deliver the request through the connection object + * + * @param request request object + * @return response object + * @see com.netscape.certsrv.client.connection.Response + */ + private synchronized Response sendRequest(Request request) + throws EAdminException { + return sendRequest(request, false); + } + + private synchronized Response sendRequest(Request request, boolean useGET) + throws EAdminException { + + try { + if (mConn == null) { + mConn = mFactory.create(mHost, mPort); + } + } catch (UnknownHostException e) { + mConn = null; + throw new EAdminException(CMSAdminResources.UNKNOWNHOST, false); + } catch (IOException e) { + retryConnection(); + throw new EAdminException(CMSAdminResources.SERVER_UNREACHABLE, false); + } catch (Exception e) { + retryConnection(); + if (Debug.isEnabled()) { + e.printStackTrace(); + } + throw new EAdminException(CMSAdminResources.UNKNOWNEXCEPTION, false); + } + + try { + return processRequest(request, useGET); + //all errors will set the connection to null + //to force re-connection and avoid null ptr exception + + } catch (Exception e) { + retryConnection(); + + try { + return processRequest(request, useGET); + } catch (InterruptedIOException ex) { + + //timeout occurred + mConn = null; + + //set time out back to original + mCurrentTimeout = mDefaultTimeout; + throw new EAdminException(CMSAdminResources.SERVER_NORESPONSE, false); + } catch (SocketException ex) { + mConn = null; + throw new EAdminException(CMSAdminResources.SERVER_UNREACHABLE, false); + } catch (IOException ex) { + if (Debug.isEnabled()) { + ex.printStackTrace(); + } + mConn = null; + throw new EAdminException(CMSAdminResources.SERVER_UNREACHABLE, false); + } catch (EAdminException ex) { + throw ex; + } catch (Exception ex) { + mConn = null; + if (Debug.isEnabled()) { + ex.printStackTrace(); + } + throw new EAdminException(CMSAdminResources.UNKNOWNEXCEPTION, false); + } + } + } + + private Response processRequest(Request request, boolean useGET) throws Exception { + //packaging the request + StringBuffer sb = new StringBuffer(); + if (useGET) { + sb.append("GET /" + request.getPrefix() + "?"); + Enumeration names = request.getElements(); + while (names.hasMoreElements()) { + String name = (String)names.nextElement(); + sb.append(name); + sb.append("="); + if (request.get(name) != null) { + sb.append(java.net.URLEncoder.encode(request.get(name))); + } + if (names.hasMoreElements()) + sb.append("&"); + } + } else { + sb.append("POST /" + request.getPrefix()); + } + sb.append(" HTTP/1.0\n"); + + StringBuffer sb1 = new StringBuffer(); + if (!useGET) { + sb.append("Content-type: application/x-www-form-urlencoded\n"); + Enumeration names = request.getElements(); + while (names.hasMoreElements()) { + String name = (String)names.nextElement(); + sb1.append(name); + sb1.append("="); + if (request.get(name) != null) { + sb1.append(java.net.URLEncoder.encode(request.get(name))); + } + if (names.hasMoreElements()) + sb1.append("&"); + } + sb.append("Content-length: " + sb1.toString().length() + "\n"); + } + + sb.append("Pragma: no-cache\n"); + if (mIsKeepAlive) { + sb.append("Connection: Keep-Alive\n"); + } + + if (mAuthType.equals("") || mAuthType.equals("pwd")) { + BasicAuthenticator auth = (BasicAuthenticator)mAuth; + // sun.misc.BASE64Encoder encoder = new sun.misc.BASE64Encoder(); + // sb.append("Authorization: Basic " + + // encoder.encodeBuffer((auth.getUserid() + + // ":" + auth.getPassword()).getBytes()) + "\n"); + sb.append("Authorization: Basic " + + b64encode((auth.getUserid() + + ":" + auth.getPassword()).getBytes()) + "\n"); + } else if (mAuthType.equals("sslclientauth")) { + sb.append("\n"); + } else { + throw new EAdminException(CMSAdminResources.AUTHENNOTSUPPORTED, false); + } + + if (!useGET) { + sb.append(sb1.toString()); + } + //Debug.println(sb.toString()); + + //System.out.println("AdminConnection: sendRequest() - sending"); + int timeout = mDefaultTimeout; + if (mCurrentTimeout > mDefaultTimeout) + timeout = mCurrentTimeout; + mConn.setSoTimeout(timeout); + mConn.sendRequest(sb.toString()); + + Response resp = new Response(mConn.getResponse()); + + if (!mIsKeepAlive) { + mConn.disconnect(); + mConn = null; + } + + //set time out back to original + mConn.setSoTimeout(mDefaultTimeout); + mCurrentTimeout = mDefaultTimeout; + return resp; + } + + private void checkParams(String dest,String scope,String id) + { + NameValuePairs pairs = new NameValuePairs(); + + checkParams(dest,scope,id,pairs); + } + + private void checkParams(String dest,String scope,String id, NameValuePairs pairs) + { + boolean bad=false; + if (dest == null) { + Debug.println("** WARNING **: 'dest' = null"); + bad = true; + } + if (scope == null) { + Debug.println("** WARNING ** : 'scope' = null"); + bad = true; + } + if (id == null) { + Debug.println("** WARNING ** : 'id' = null"); + bad = true; + } + if (pairs == null) { + Debug.println("** WARNING ** : 'pairs' = null"); + bad = true; + } + if (bad) { + Debug.println("dest = "+dest); + Debug.println("scope = "+scope); + Debug.println("id = "+id); + Debug.println("---------"); + } + } +} diff --git a/base/console/src/com/netscape/admin/certsrv/connection/BasicAuthenticator.java b/base/console/src/com/netscape/admin/certsrv/connection/BasicAuthenticator.java new file mode 100644 index 000000000..1d3796968 --- /dev/null +++ b/base/console/src/com/netscape/admin/certsrv/connection/BasicAuthenticator.java @@ -0,0 +1,54 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.admin.certsrv.connection; + +import java.io.*; +import java.util.*; + +/** + * An interface represents authentiator. + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class BasicAuthenticator implements IAuthenticator { + + private String mUserid = null; + private String mPassword = null; + + public BasicAuthenticator(String userid, String password) { + mUserid = userid; + mPassword = password; + } + + public String getUserid() { + return mUserid; + } + + public String getPassword() { + return mPassword; + } + + public void setUserId(String userid) { + mUserid = userid; + } + + public void setPassword(String password) { + mPassword = password; + } +} diff --git a/base/console/src/com/netscape/admin/certsrv/connection/IAuthenticator.java b/base/console/src/com/netscape/admin/certsrv/connection/IAuthenticator.java new file mode 100644 index 000000000..c91b7d8bc --- /dev/null +++ b/base/console/src/com/netscape/admin/certsrv/connection/IAuthenticator.java @@ -0,0 +1,30 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.admin.certsrv.connection; + +import java.io.*; +import java.util.*; + +/** + * An interface represents authentiator. + * + * @author thomask + * @version $Revision$, $Date$ + */ +public interface IAuthenticator { +} diff --git a/base/console/src/com/netscape/admin/certsrv/connection/IConnection.java b/base/console/src/com/netscape/admin/certsrv/connection/IConnection.java new file mode 100644 index 000000000..0643e50eb --- /dev/null +++ b/base/console/src/com/netscape/admin/certsrv/connection/IConnection.java @@ -0,0 +1,55 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.admin.certsrv.connection; + +import java.io.IOException; +import java.net.SocketException; + +/** + * Interface for all connection objects. Primarily act as + * the abstartion layer for SSLavaConnection and SSLConnection. + * + * @author Jack Pan-Chen + * @version $Revision$, $Date$ + * @see com.netscape.certsrv.client.connection.SSLavaConnection + * @see com.netscape.certsrv.client.connection.SSLConnection + */ +public interface IConnection { + + /** + * Send request to the server using this connection + */ + public int sendRequest(String req) throws IOException; + + /** + * Returns the response in byte array format + */ + public byte[] getResponse(); + + /** + * Close the connection + */ + public void disconnect(); + + /** + * SetTimeout + */ + public void setSoTimeout(int timeout) throws SocketException; + + +} diff --git a/base/console/src/com/netscape/admin/certsrv/connection/IConnectionFactory.java b/base/console/src/com/netscape/admin/certsrv/connection/IConnectionFactory.java new file mode 100644 index 000000000..4c8573f23 --- /dev/null +++ b/base/console/src/com/netscape/admin/certsrv/connection/IConnectionFactory.java @@ -0,0 +1,40 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.admin.certsrv.connection; + +import java.net.*; +import java.io.*; + +/** + * Interface for all connection factory. Primarily act as + * the abstartion layer for different kind of connection factory. + * + * @author Jack Pan-Chen + * @version $Revision$, $Date$ + * @see com.netscape.certsrv.client.connection + */ +public interface IConnectionFactory { + + /** + * Creates connection using the host and port + */ + public IConnection create(String host, int port) + throws IOException, UnknownHostException; + +} + diff --git a/base/console/src/com/netscape/admin/certsrv/connection/JSSConnection.java b/base/console/src/com/netscape/admin/certsrv/connection/JSSConnection.java new file mode 100644 index 000000000..27292b3d9 --- /dev/null +++ b/base/console/src/com/netscape/admin/certsrv/connection/JSSConnection.java @@ -0,0 +1,761 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.admin.certsrv.connection; + +import java.util.*; +import java.net.*; +import java.io.*; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import com.netscape.admin.certsrv.*; +import com.netscape.certsrv.common.*; +import com.netscape.management.client.util.Debug; +import com.netscape.management.client.util.*; +import org.mozilla.jss.ssl.*; +import org.mozilla.jss.*; +import org.mozilla.jss.util.*; +import org.mozilla.jss.crypto.*; +import org.mozilla.jss.pkcs11.*; +import javax.swing.*; +import java.awt.*; + +/** + * JSSConnection deals with establishing a connection to + * a server, sending requests and reading responses. + * + * XXX - Performance optimizations if any, persistent connection + * support, server auth verification and client authentication + * support to be added. NEED TO COME BACK AND CLEAN UP - coding + * standard. + * + * @author Jack Pan-Chen + * @author kanda + * @author Christine Ho + * @version $Revision$, $Date$ + */ +public class JSSConnection implements IConnection, SSLCertificateApprovalCallback, + SSLClientCertificateSelectionCallback { + + /*========================================================== + * variables + *==========================================================*/ + + /* static variables */ + static CryptoManager cryptoManager; + static CertificateFactory cf; + static SelectCertDialog selectCertDialog = null; + static PromptForTrustDialog promptForTrustDialog = null; + + /* private valiable */ + private InputStream httpIn; + private OutputStream httpOut; + private byte[] body; + private int bodyLen; + private String header; + private int available; + private int totalRead; + private boolean endOfHeader = false; + + private static int HTTP_OK_RESPONSE = 200; + private static final String PANELNAME = "SSLCLIENT"; + private boolean abort = false;; + private boolean mClientAuth = false; + private boolean mCertAccepted = true; + private boolean mClientCertFound = true; + private boolean mServerCertImported = true; + private boolean mTokenPasswordInit = true; + private boolean mTokenPasswdSame = true; + + protected SSLSocket s = null; + + /*========================================================== + * constructors + *==========================================================*/ + public JSSConnection(String host, int port) + throws IOException, UnknownHostException { + + UtilConsoleGlobals.initJSS(); + cf = UtilConsoleGlobals.getX509CertificateFactory(); + try { + cryptoManager = CryptoManager.getInstance(); + } catch (Exception e) { + } + + // SSLSocket needs to be set before getting an instance + // to get the ciphers + SSLSocket.enableSSL2Default(false); + SSLSocket.enableSSL3Default(true); + int TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA = 0xC005; + int TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = 0xC00A; + + int ciphers[] = SSLSocket.getImplementedCipherSuites(); + for (int i = 0; ciphers != null && i < ciphers.length; i++) { + // make sure SSLv2 ciphers are not enabled + if ((ciphers[i] & 0xfff0) !=0xff00) { + Debug.println("JSSConnection Debug: non-SSL2 NSS Cipher Supported '0x" + + Integer.toHexString(ciphers[i]) + "'"); + SSLSocket.setCipherPreferenceDefault(ciphers[i], true); + } else { + Debug.println("JSSConnection Debug: SSL2 (turned off) NSS Cipher Supported '0x" + + Integer.toHexString(ciphers[i]) + "'"); + SSLSocket.setCipherPreferenceDefault(ciphers[i], false); + } + + /* Enable ECC Cipher */ + + if (ciphers[i] == TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA) { + Debug.println("JSSConnection Debug: found TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, setting preference"); + SSLSocket.setCipherPreferenceDefault(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, true); + } + if (ciphers[i] == TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) { + Debug.println("JSSConnection Debug: found TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, setting preference"); + SSLSocket.setCipherPreferenceDefault(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, true); + } + } + s = new SSLSocket(host, port, null, 0, this, this); + s.enableSSL2(false); + s.enableSSL2Default(false); + s.enableV2CompatibleHello(false); + s.enableSSL3(true); + s.enableSSL3Default(true); + + // Initialze Http Input and Output Streams + httpIn = s.getInputStream(); + httpOut = s.getOutputStream(); + cryptoManager.setPasswordCallback(new pwcb()); + Debug.println("JSSConnection Debug: end of JSSConnection constructor"); + } + + public boolean approve(org.mozilla.jss.crypto.X509Certificate serverCert, + ValidityStatus status) + { + if (!mCertAccepted) + return false; + + boolean promptForTrust = true; + + //if server auth is not enabled + if (!(UtilConsoleGlobals.isServerAuthEnabled())) { + return mCertAccepted; + } + + Enumeration errors = status.getReasons(); + //if there are more then 1 error we need to propmt user for trust + promptForTrust = errors.hasMoreElements(); + + /* if trusted already */ + if (!promptForTrust) + return mCertAccepted; + + //the x509certificate pass in by jss is lacking some + //api. so I am getting the encoding then + //use the default security provider provided by sun + //to decode certificate. + //due to the fact that current JSS(version2.1) will clobber + //the way jdk loads the default sun security provider I am + //using the workaround for now. Which is to load the sun + //provider before jss is loaded. (see static section above) + X509Certificate x509Cert = null; + try { + ByteArrayInputStream bais = new ByteArrayInputStream(serverCert.getEncoded()); + + while (bais.available() > 0) { + x509Cert = (X509Certificate)(cf.generateCertificate(bais)); + Debug.println(x509Cert.toString()); + } + } catch (Exception e) { + e.printStackTrace(); + } + + //bring up the trust dialog + promptForTrustDialog = new PromptForTrustDialog(getFrame(), x509Cert, status); + promptForTrustDialog.setVisible(true); + mCertAccepted = promptForTrustDialog.isCertAccepted(); + if (mCertAccepted) { + //user want to save this certificate not just this session + //so we have to store the cert as perm cert. + if (!(promptForTrustDialog.isAcceptedForOneSession())) { + try { + String nickname = serverCert.getNickname(); + + CryptoToken internalToken = + cryptoManager.getInternalKeyStorageToken(); + + if (!internalToken.passwordIsInitialized()) { + InitPasswordDialog initPasswordDialog = + new InitPasswordDialog(internalToken); + initPasswordDialog.setVisible(true); + if (initPasswordDialog.isCancel()) { + mTokenPasswordInit = false; + return false; + } + if (!initPasswordDialog.isPwdSame()) { + mTokenPasswdSame = false; + mTokenPasswordInit = false; + return false; + } + if (!initPasswordDialog.isTokenInit()) { + mTokenPasswordInit = false; + return false; + } + } + + if (!internalToken.isLoggedIn()) { + internalToken.login(new pwcb()); + } + if (abort) { + mServerCertImported = false; + mCertAccepted = false; + return false; + } + InternalCertificate internalCert = + cryptoManager.importCertToPerm(serverCert, + (nickname==null)?serverCert.getSubjectDN().toString():nickname); + internalCert.setSSLTrust( + org.mozilla.jss.crypto.InternalCertificate.TRUSTED_PEER | + org.mozilla.jss.crypto.InternalCertificate.VALID_PEER); + } catch (Exception e) { + mServerCertImported = false; + mCertAccepted = false; + if (Debug.getTrace()) { + e.printStackTrace(); + } + return false; + } + } + } + + return mCertAccepted; + } + + public boolean isSamePwd() { + return mTokenPasswdSame; + } + + public boolean isTokenPasswordInit() { + return mTokenPasswordInit; + } + + public boolean hasClientCert() { + return mClientCertFound; + } + + public boolean isClientAuth() { + return mClientAuth; + } + + public boolean isCertAccepted() { + return mCertAccepted; + } + + public boolean isAbortAction() { + return abort; + } + + public boolean isServerCertImported() { + return mServerCertImported; + } + + public String select(Vector nicknames) + { + selectCertDialog = null; + mClientAuth = true; + if (nicknames == null || nicknames.size() == 0) { + mClientCertFound = false; + return ""; + } + + selectCertDialog = new JSSConnection.SelectCertDialog(); + + Debug.println("JSSConnection::select(...) - SELECT CERTIFICATE"); + selectCertDialog.setCertList(nicknames); + selectCertDialog.setVisible(true); + return (selectCertDialog.isCancel()?"":selectCertDialog.getSelectedCert()); + } + + public class pwcb implements PasswordCallback { + private int nthPrompt = 0; + private static final int MAX_PASSWORD_PROMPT = 20; + GetPasswordDialog getPasswordDialog = null; + + public Password getPasswordFirstAttempt(PasswordCallbackInfo info) + throws PasswordCallback.GiveUpException { + + if (abort) + throw new PasswordCallback.GiveUpException(); + + nthPrompt++; + + if (getPasswordDialog == null) + getPasswordDialog = new GetPasswordDialog(); + + getPasswordDialog.setPasswordInfo(info, false); + getPasswordDialog.setVisible(true); + + if (getPasswordDialog.isCancel()) { + nthPrompt = 0; + abort = true; + throw new PasswordCallback.GiveUpException(); + } + + return getPasswordDialog.getPassword(); + } + + public Password getPasswordAgain(PasswordCallbackInfo info) + throws GiveUpException + { + + if (abort) + throw new PasswordCallback.GiveUpException(); + nthPrompt++; + if (nthPrompt > MAX_PASSWORD_PROMPT || getPasswordDialog.isCancel()) { + nthPrompt = 0; + abort = true; + throw new PasswordCallback.GiveUpException(); + } + + getPasswordDialog.setPasswordInfo(info, true); + getPasswordDialog.setVisible(true); + + return getPasswordDialog.getPassword(); + } + } + + /*========================================================== + * public methods + *==========================================================*/ + + /** + * Send request to the server using this connection + * + * @param req request object + * @return status 1-success, 0- failed + * @excpetion IOExcpetion + */ + public int sendRequest(String req) + throws IOException { + + int stat = 1; + if (req == null) + { + //System.out.println("Request is null"); + return 0; + } + endOfHeader = false; + + PrintStream ps = new PrintStream(httpOut); + ps.println(req); + ps.println(); + ps.flush(); + try + { + Thread.sleep(100); + } + catch (Exception e) { + Debug.println("JSSConnection Debug: in sendRequest:"+e.toString()); + System.out.println("sleeping "+e.toString()); + } + //System.out.println("Request Sent - bytes:" + httpOut.getTotal()); + + // Init the Reply stream + totalRead = 0; + header = null; + initReadResponse(); + return stat; + } + + /** + * Retrieve the input stream + */ + public InputStream getInputStream() + throws IOException { + + return s.getInputStream(); + } + + /** + * Read + */ + public int read(byte[] buf) + throws IOException { + + return httpIn.read(buf, 0, buf.length); + } + + /** + * Get Header + */ + public String getHeader() { + if (header == null) + return "No Header Read"; + else + return header; + } + + /** + * Get response + */ + public byte[] getResponse() { + if (totalRead == 0) + return null; + else { + byte[] buf = new byte[bodyLen]; + System.arraycopy(body, 0, buf, 0, bodyLen); + return buf; + } + } + + /** + * get available + */ + public int available() + throws IOException { + + return httpIn.available(); + } + + /** + * Disconnect this connection + */ + public void disconnect() { + try { + s.close(); + } catch (Exception e) { + //ignor ? + } + } + + /** + * Set time out + */ + public void setSoTimeout(int timeout) throws SocketException { + //System.out.println("JSSConnection: setSoTimeout() - "+timeout); + s.setSoTimeout(timeout); + } + + /*========================================================== + * private methods + *==========================================================*/ + + private JFrame getFrame() { + if (UtilConsoleGlobals.getActivatedFrame() != null) + return UtilConsoleGlobals.getActivatedFrame(); + return new JFrame(); + } + + private void initReadResponse() + throws IOException { + + readHeader(); + readBody(); + } + + private int readLineFromStream(InputStream is, byte line[], + int startpos, int len) throws IOException { + //return is.readLine(line, startpos, len); + int pos = startpos; + int count = 0; + while (len > 0) + { + int nRead = httpIn.read(line, pos, 1); + if (nRead == -1) + break; + count++; + if (line[pos] == '\n') { + break; + } + pos++; + } + return count > 0 ? count : -1; + } + + private void readHeader() throws IOException + { + // Read the status line of response and parse for + // Errors. + byte[] headerLine = new byte[1096]; + int nRead = readLineFromStream(httpIn, headerLine, 0, 1096); + + //System.out.println("XXX read " + nRead); + + if (requestFailed(new String(headerLine))) { + Debug.println("JSSConnection Debug: in readHeader requestFailed"); + throw new IOException(getReasonPhrase(new String (headerLine))); + } + + while (true) { + nRead = readLineFromStream(httpIn, headerLine, 0, 1096); + int available = httpIn.available(); + + //System.out.println("Available: " + available); + + if (nRead == -1) { + System.out.println("Unexpected end of stream"); + break; + } + + processHeader(headerLine, nRead); + + if (endOfHeader) { + //System.out.println("End of Header"); + break; + } else { + //System.out.println("Header: " + new String(headerLine) + // + ", nRead: " + nRead); + } + } + } + + private boolean endOfHeader(byte[] hdr, int available) { + if (available == 2) { + int c1 = (int)hdr[0]; + int c2 = (int)hdr[1]; + + //System.out.println("C1= " + c1); + //System.out.println("C2= " + c2); + + return true; + } else + return false; + } + + private void readBody() + throws IOException { + + body = new byte[bodyLen]; + totalRead = 0; + while (totalRead < bodyLen) { + int nRead = httpIn.read(body, totalRead, bodyLen - totalRead); + totalRead += nRead; + } + } + + + private void processHeader(byte[] buf, int nRead) + { + if (endOfHeader(buf, nRead)) { + endOfHeader = true; + return; + } + + String hdr = new String(buf, 0, nRead); + int index = 0; + if (hdr.toLowerCase().startsWith("content-length: ")) { + try { + String length = hdr.substring(hdr.indexOf(": ") + 1); + bodyLen = Integer.parseInt(length.trim()); + return; + } catch (Exception e){e.printStackTrace(); } + } + } + + private boolean requestFailed(String header) { + return (header.indexOf(Integer.toString(HTTP_OK_RESPONSE)) > 0) ? false: true; + } + + private String getReasonPhrase(String header) { + String str1 = header.substring(header.indexOf(' ') +1); + return str1.substring(str1.indexOf(' ') +1); + } + + class InitPasswordDialog extends AbstractDialog { + protected ResourceBundle mResource = + ResourceBundle.getBundle(CMSAdminResources.class.getName()); + SingleBytePasswordField pwd; + SingleBytePasswordField pwdAgain; + CryptoToken mToken; + boolean tokenPasswdInit = true; + boolean pwdSame = true; + + public InitPasswordDialog(CryptoToken token) { + super(null,"",true, OK|CANCEL); + setMinimumSize(300, 150); + mToken = token; + setTitle(mResource.getString("SSLCLIENT_INITPASSWORD_DIALOG_TITLE")); + Container p = getContentPane(); + p.setLayout(new GridBagLayout()); + + int y = 0; + pwd = new SingleBytePasswordField(); + pwdAgain = new SingleBytePasswordField(); + JLabel pwdLbl = new JLabel(); + JLabel pwdAgainLbl = new JLabel(); + pwdLbl.setText(mResource.getString("SSLCLIENT_INITPASSWORD_PWD_LABEL")); + pwdAgainLbl.setText( + mResource.getString("SSLCLIENT_INITPASSWORD_PWDAGAIN_LABEL")); + GridBagUtil.constrain(p, pwdLbl, + 0, y, 1, 1, + 0.0, 0.0, + GridBagConstraints.EAST, GridBagConstraints.NONE); + GridBagUtil.constrain(p, pwd, + 1, y, GridBagConstraints.REMAINDER, 1, + 1.0, 0.0, + GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL); + GridBagUtil.constrain(p, pwdAgainLbl, + 0, ++y, 1, 1, + 0.0, 0.0, + GridBagConstraints.WEST, GridBagConstraints.NONE); + GridBagUtil.constrain(p, pwdAgain, + 1, y, GridBagConstraints.REMAINDER, 1, + 1.0, 0.0, + GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL); +/* + GridBagUtil.constrain(p, pwd, + 0, ++y, 1, 1, + 1.0, 0.0, + GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, + 0, 0, 0, 0); +*/ + + pack(); + } + + protected void okInvoked() { + if (!pwd.getText().equals(pwdAgain.getText())) { + pwdSame = false; + dispose(); + return; + } + + try { + mToken.initPassword(null, getPassword()); + dispose(); + } catch (Exception e) { + tokenPasswdInit = false; + } + } + + public boolean isPwdSame() { + return pwdSame; + } + + public boolean isTokenInit() { + return tokenPasswdInit; + } + + public void setVisible(boolean visible) { + pack(); + pwd.grabFocus(); + super.setVisible(visible); + } + + public Password getPassword() { + Password jssPwd = new Password(pwd.getText().toCharArray()); + return jssPwd; + } + } + + class GetPasswordDialog extends AbstractDialog { + + MultilineLabel enterPwdLabel = new MultilineLabel(); + protected ResourceBundle mResource = + ResourceBundle.getBundle(CMSAdminResources.class.getName()); + SingleBytePasswordField pwd; + public GetPasswordDialog() { + super(null,"",true, OK|CANCEL); + setTitle(mResource.getString("SSLCLIENT_PASSWORD_DIALOG_TITLE")); + Container p = getContentPane(); + p.setLayout(new GridBagLayout()); + + int y = 0; + GridBagUtil.constrain(p, enterPwdLabel, + 0, y, 1, 1, + 1.0, 0.0, + GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, + 0, 0, 0, 0); + + pwd = new SingleBytePasswordField(); + GridBagUtil.constrain(p, pwd, + 0, ++y, 1, 1, + 1.0, 0.0, + GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, + 0, 0, 0, 0); + + pack(); + } + + public void setVisible(boolean visible) { + pack(); + pwd.grabFocus(); + super.setVisible(visible); + } + + public void setPasswordInfo(PasswordCallbackInfo info, boolean getPwdAgain) { + if (getPwdAgain) + enterPwdLabel.setText(mResource.getString( + "SSLCLIENT_PASSWORDAGAIN_DIALOG_LABEL")+" "+info.getName()+":"); + else + enterPwdLabel.setText(mResource.getString( + "SSLCLIENT_PASSWORD_DIALOG_LABEL")+" "+ info.getName()+":"); + Debug.println(info.getName()); + } + + public Password getPassword() { + Password jssPwd = new Password(pwd.getText().toCharArray()); + return jssPwd; + } + } + + + class SelectCertDialog extends AbstractDialog { + + JComboBox certList = new JComboBox(); + protected ResourceBundle mResource = ResourceBundle.getBundle( + CMSAdminResources.class.getName()); + public SelectCertDialog() { + super(null,"", true, OK|CANCEL); + setTitle(mResource.getString("SSLCLIENT_CERTSELECT_DIALOG_TITLE")); + + Container p = getContentPane(); + p.setLayout(new GridBagLayout()); + + int y = 0; + GridBagUtil.constrain(p, new JLabel( + mResource.getString("SSLCLIENT_CERTSELECT_DIALOG_LABEL")), + 0, y, 1, 1, + 1.0, 0.0, + GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, + 0, 0, 0, 0); + + GridBagUtil.constrain(p, certList, + 0, ++y, 1, 1, + 1.0, 0.0, + GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, + 0, 0, 0, 0); + pack(); + } + + public void setCertList(Vector nicknames) { + certList.removeAllItems(); + Enumeration enum1 = nicknames.elements(); + while (enum1.hasMoreElements()) { + certList.insertItemAt(enum1.nextElement(), 0); + } + try { + certList.setSelectedIndex(0); + } catch (Exception e) { + } + } + + public String getSelectedCert() { + return certList.getSelectedItem().toString(); + } + + } + +} diff --git a/base/console/src/com/netscape/admin/certsrv/connection/PromptForTrustDialog.java b/base/console/src/com/netscape/admin/certsrv/connection/PromptForTrustDialog.java new file mode 100644 index 000000000..868eccc1b --- /dev/null +++ b/base/console/src/com/netscape/admin/certsrv/connection/PromptForTrustDialog.java @@ -0,0 +1,316 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +//package com.netscape.management.client.security; +package com.netscape.admin.certsrv.connection; + +import com.netscape.management.nmclf.SuiConstants; +import com.netscape.management.nmclf.SuiLookAndFeel; +import com.netscape.management.client.util.*; +import com.netscape.admin.certsrv.ug.*; + +import java.awt.event.*; +import java.awt.*; +import javax.swing.*; +import java.io.*; +import java.util.*; +import java.net.*; +import java.text.*; +import java.security.cert.X509Certificate; +import com.netscape.admin.certsrv.*; +import com.netscape.certsrv.common.*; + +import org.mozilla.jss.ssl.SSLCertificateApprovalCallback.ValidityStatus; + +/** + * Dialog box that prompts user to either accept or reject + * an untrusted certificate. + */ +public class PromptForTrustDialog extends AbstractDialog implements SuiConstants { + + private static boolean certIsAccepted = false; + private static boolean acceptedForSingleSession = false; + private X509Certificate mCert; + + private UserConfirmationActionListener buttonActionListener = + new UserConfirmationActionListener(); + protected ResourceBundle mResource; + //static ResourceSet _resource = new ResourceSet("com.netscape.admin.certsrv.connection.ServerAuthResource"); + + CertViewDialog viewCertDialog; + //ViewCertificateDialog viewCertDialog; + JCheckBox oneSession; + + + /** + * create a dialog that prompt user to either accept or reject an untrusted certificate + * @param parent the owner of the dialog + * @param cert certificate chain + * @param certChain_errCode cert chain errors (0 if no errors) + * @param serverCert_errCode server cert errors (0 if no errors) + * + * + */ + public PromptForTrustDialog(Frame parent, X509Certificate cert, + ValidityStatus status) { + super(parent, "", true); + mResource = ResourceBundle.getBundle( + CMSAdminResources.class.getName()); + mCert = cert; + + setTitle(mResource.getString("SSLCLIENT_TRUST_DIALOG_TITLE")); + + getContentPane().setLayout(new GridBagLayout()); + + + //Add action button pane first so the accept button will + //get default focus. Already try various way with *Focus() call + //none of them work. + GridBagUtil.constrain(getContentPane(), createActionButtons(), + 0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.SOUTHEAST, + GridBagConstraints.NONE, 0, 0, 0, 0); + + GridBagUtil.constrain(getContentPane(), siteAlert(), 0, 0, 1, + 1, 1.0, 1.0, GridBagConstraints.NORTH, + GridBagConstraints.BOTH, VERT_WINDOW_INSET, + VERT_WINDOW_INSET, 0, 0); + + //viewCertDialog = new ViewCertificateDialog(parent, cert, status); + viewCertDialog = new CertViewDialog((JFrame)parent); + + setMinimumSize(400, 250); + if (parent == null) { + ModalDialogUtil.setCenteredDialog(this); + } + pack(); + } + + + /** + * Handles all the action (Ok, Accept, Reject, and Help) + * + */ + class UserConfirmationActionListener implements ActionListener { + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("ACCEPT")) { + certIsAccepted = true; + setVisible(false); + } else if (e.getActionCommand().equals("REJECT")) { + certIsAccepted = false; + setVisible(false); + } else if (e.getActionCommand().equals("VIEWCERT")) { + String certContent = getPrettyPrint(mCert); + viewCertDialog.showDialog("", certContent); + } + } + } + + private final static String spaces = + " " + + " " + + " " + + " " + + " "; + private static final char[] hexdigits = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F' + }; + + private String indent(int size) { + return spaces.substring(0, size); + } + + private String getPrettyPrint(X509Certificate cert) { + String subjectdn = cert.getSubjectDN().toString(); + String issuerdn = cert.getIssuerDN().toString(); + String serial = cert.getSerialNumber().toString(); + SimpleDateFormat formatter = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy"); + String before = formatter.format(cert.getNotBefore()); + String after = formatter.format(cert.getNotAfter()); + String fingerprint = getHexString(cert.getSignature(), 16, 16, ":"); + String str = "Subject name: "+subjectdn+"\n"+ + "Issuer name: "+issuerdn+"\n"+"Serial number: "+serial+"\n"+ + "Validity: "+before+" to "+after+"\n"+"Signature:\n"+ + fingerprint+"\n"; + return str; + } + + private String getHexString(byte[] in, int indentSize, int lineLen, + String separator) { + StringBuffer sb = new StringBuffer(); + int hexCount = 0; + char c[]; + int j = 0; + + if (lineLen == 0) { + c = new char[in.length * 3 + 1]; + } else { + c = new char[lineLen * 3 + 1]; + } + + char sep = separator.charAt(0); + + sb.append(indent(indentSize)); + for (int i = 0; i < in.length; i++) { + if (lineLen > 0 && hexCount == lineLen) { + c[j++] = '\n'; + sb.append(c, 0, j); + sb.append(indent(indentSize)); + hexCount = 0; + j = 0; + } + byte x = in[i]; + + // output hex digits to buffer + c[j++] = hexdigits[(char) ((x >> 4) & 0xf)]; + c[j++] = hexdigits[(char) (x & 0xf)]; + + // if not last char, output separator + if (i != in.length - 1) { + c[j++] = sep; + } + + hexCount++; + } + if (j > 0) { + c[j++] = '\n'; + sb.append(c, 0, j); + } + // sb.append("\n"); + + return sb.toString(); + } + + /** + * @return true if certificate is accepted + */ + public boolean isCertAccepted() { + return certIsAccepted; + } + + /** + * @return true certificate should only be accept for a single session + */ + public boolean isAcceptedForOneSession() { + return oneSession.isSelected(); + } + + + /** + * Allow reuse of this dialog, if it is not disposed. + * @param cert certificate chain + * @param certChain_errCode cert chain errors (0 if no errors) + * @param serverCert_errCode server cert errors (0 if no errors) + * + */ + public void setCertificateInfo(X509Certificate cert, + ValidityStatus status) { + //viewCertDialog.setCertificate(cert, status); + } + + + /** + * Create a warning message panel + */ + private JPanel siteAlert() { + JPanel notTrustedSiteWarning = new JPanel(); + notTrustedSiteWarning.setLayout(new GridBagLayout()); + + JLabel warningImage = new JLabel(UIManager.getIcon("OptionPane.warningIcon")); + MultilineLabel warningMsg = new MultilineLabel( + mResource.getString("SSLCLIENT_TRUST_DIALOG_WARNMSG")); + oneSession = new JCheckBox( + mResource.getString("SSLCLIENT_TRUST_DIALOG_ACCEPTONESESSION"), + false); + + GridBagUtil.constrain(notTrustedSiteWarning, warningImage, 0, + 0, 1, 1, 0.0, 0.0, GridBagConstraints.NORTHWEST, + GridBagConstraints.NONE, 0, 0, 0, + DIFFERENT_COMPONENT_SPACE); + + GridBagUtil.constrain(notTrustedSiteWarning, warningMsg, 1, 0, + 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, + GridBagConstraints.BOTH, 0, 0, + DIFFERENT_COMPONENT_SPACE, VERT_WINDOW_INSET); + + GridBagUtil.constrain(notTrustedSiteWarning, oneSession, 1, 1, + 1, 1, 0.0, 0.0, GridBagConstraints.SOUTHWEST, + GridBagConstraints.NONE, 0, 0, 0, VERT_WINDOW_INSET); + + GridBagUtil.constrain(notTrustedSiteWarning, + Box.createVerticalGlue(), 1, 2, 2, 1, 1.0, 1.0, + GridBagConstraints.NORTH, GridBagConstraints.BOTH, 0, + 0, 0, 0); + return notTrustedSiteWarning; + } + + JButton accept; + public void setVisible(boolean visible) { + if (visible) { + accept.grabFocus(); + setDefaultButton(accept); + } + super.setVisible(visible); + } + + /** + * create all the action buttons (Accept, Reject, View Certificate, and Help) + */ + private JPanel createActionButtons() { + JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new GridBagLayout()); + + accept = JButtonFactory.create( + mResource.getString("SSLCLIENT_TRUST_DIALOG_ACCEPT"), + buttonActionListener, "ACCEPT"); + accept.registerKeyboardAction(buttonActionListener, "ACCEPT", + KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), + JComponent.WHEN_IN_FOCUSED_WINDOW); + + JButton reject = JButtonFactory.create( + mResource.getString("SSLCLIENT_TRUST_DIALOG_REJECT"), + buttonActionListener, "REJECT"); + reject.registerKeyboardAction(buttonActionListener, "REJECT", + KeyStroke.getKeyStroke(KeyEvent.VK_R, 0), + JComponent.WHEN_IN_FOCUSED_WINDOW); + + JButton viewCert = JButtonFactory.create( + mResource.getString("SSLCLIENT_TRUST_DIALOG_VIEWCERT"), buttonActionListener, "VIEWCERT"); + viewCert.registerKeyboardAction(buttonActionListener, "VIEWCERT", + KeyStroke.getKeyStroke(KeyEvent.VK_V, 0), + JComponent.WHEN_IN_FOCUSED_WINDOW); + JButtonFactory.resizeGroup(accept, reject); + + int x = 0; + GridBagUtil.constrain(buttonPanel, accept, x, 0, 1, 1, 0.0, + 0.0, GridBagConstraints.NORTH, + GridBagConstraints.BOTH, DIFFERENT_COMPONENT_SPACE, 0, + 0, COMPONENT_SPACE); + + GridBagUtil.constrain(buttonPanel, reject, ++x, 0, 1, 1, 0.0, + 0.0, GridBagConstraints.NORTH, + GridBagConstraints.BOTH, DIFFERENT_COMPONENT_SPACE, 0, + 0, COMPONENT_SPACE); + + GridBagUtil.constrain(buttonPanel, viewCert, ++x, 0, 1, 1, 0.0, + 0.0, GridBagConstraints.NORTH, + GridBagConstraints.BOTH, DIFFERENT_COMPONENT_SPACE, 0, + 0, DIFFERENT_COMPONENT_SPACE); + + return buttonPanel; + } +} diff --git a/base/console/src/com/netscape/admin/certsrv/connection/Request.java b/base/console/src/com/netscape/admin/certsrv/connection/Request.java new file mode 100644 index 000000000..8ed61e998 --- /dev/null +++ b/base/console/src/com/netscape/admin/certsrv/connection/Request.java @@ -0,0 +1,70 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.admin.certsrv.connection; + +import java.io.*; +import java.util.*; + +/** + * A class represents a connection to certificate server. + * + * @author thomask + * @author Jack Pan-Chen + * @version $Revision$, $Date$ + */ +public class Request { + + private String mPrefix = null; + + //internal structure is changed to vector to maintain + //the ordering + + private Vector mName = new Vector(); + private Vector mValue = new Vector(); + + public Request(String prefix) { + mPrefix = prefix; + } + + public String getPrefix() { + return mPrefix; + } + + public void set(String name, String value) { + mName.addElement(name); + mValue.addElement(value); + } + + public String get(String name) { + int i = mName.indexOf(name); + try { + return (String) mValue.elementAt(i); + } catch (ArrayIndexOutOfBoundsException e) { + return ""; + } + } + + public Enumeration getElements() { + return mName.elements(); + } + + public void removeAll() { + mName.removeAllElements(); + mValue.removeAllElements(); + } +} diff --git a/base/console/src/com/netscape/admin/certsrv/connection/Response.java b/base/console/src/com/netscape/admin/certsrv/connection/Response.java new file mode 100644 index 000000000..bbb511443 --- /dev/null +++ b/base/console/src/com/netscape/admin/certsrv/connection/Response.java @@ -0,0 +1,133 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.admin.certsrv.connection; + +import java.net.*; +import java.io.*; +import java.util.*; + +/** + * Response - now use vector to maintain the oredering + * + * @author kanda + * @author thomask + * @author Jack Pan-Chen + * @version $Revision$, $Date$ + */ +public class Response { + boolean debug = true; + boolean test = true; + boolean testsuccess = true; // test success condition? + + public static final int SUCCESS = 0; + public static final int RESTART = -1; + + private int mRetcode; + private String mErrorMsg; + + //internal structure is changed to vector to maintain + //the ordering + + private Vector mName = new Vector(); + private Vector mValue = new Vector(); + + public Response() { + // for testing only + + } + + public Response(byte[] resp) throws IOException { + ByteArrayInputStream bis = new ByteArrayInputStream(resp); + DataInputStream dis = new DataInputStream(bis); + mRetcode = dis.readInt(); + byte[] mContents = null; + + if (debug) + //System.out.println("===in Response===\n"); + + if ((mRetcode != SUCCESS) && (mRetcode != RESTART)) { + mErrorMsg = dis.readUTF(); + } else { + if (resp.length > 4) { + mContents = new byte[resp.length - 4]; + dis.read(mContents); + } + } + if (mContents != null) { + String resultStr = new String(mContents); + StringTokenizer st = new StringTokenizer(resultStr, + "&"); + while (st.hasMoreTokens()) { + String p = st.nextToken(); + int i = p.indexOf("="); + if (i == -1) { + return; + } + String t = URLdecode(p.substring(0, i)); + String v = URLdecode(p.substring(i + 1)); + mName.addElement(t); + mValue.addElement(v); + } + } + } + + public int getReturnCode() { + return mRetcode; + } + + public String getErrorMessage() { + return mErrorMsg; + } + + /** + * URL decodes the given string. + */ + public String URLdecode(String s) { + if (s == null) + return null; + ByteArrayOutputStream out = new ByteArrayOutputStream(s.length()); + for (int i = 0; i < s.length(); i++) { + int c = (int) s.charAt(i); + if (c == '+') { + out.write(' '); + } else if (c == '%') { + int c1 = Character.digit(s.charAt(++i), 16); + int c2 = Character.digit(s.charAt(++i), 16); + out.write((char) (c1 * 16 + c2)); + } else { + out.write(c); + } + } // end for + return out.toString(); + } + + public Enumeration getNames() { + return mName.elements(); + } + + public String get(String name) { + int i = mName.indexOf(name); + String value; + try { + value = (String) mValue.elementAt(i); + } catch (ArrayIndexOutOfBoundsException e) { + value = ""; + } + return value; + } +} diff --git a/base/console/src/com/netscape/admin/certsrv/connection/SSLConnectionFactory.java b/base/console/src/com/netscape/admin/certsrv/connection/SSLConnectionFactory.java new file mode 100644 index 000000000..7c74a239d --- /dev/null +++ b/base/console/src/com/netscape/admin/certsrv/connection/SSLConnectionFactory.java @@ -0,0 +1,81 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.admin.certsrv.connection; + +import java.net.*; +import java.io.*; + +/** + * SSLConnectionFactory - factory method for creating supported SSL + * Connection type: SSLAVA_CONNECTION, SSL_CONNECTION. DEFAULT connection + * SSLAVA_CONNECTION will be used if type specified is incorrect. + * + * + * @author Jack Pan-Chen + * @version $Revision$, $Date$ + * @see com.netscape.certsrv.client.connection + */ +public class SSLConnectionFactory implements IConnectionFactory { + + /*========================================================== + * variables + *==========================================================*/ + public static final String JSS_CONNECTION = "JSS"; + public static final String SSL_CONNECTION = "SSL"; + + private String mType; + + /*========================================================== + * constructors + *==========================================================*/ + + /** + * Construct a specific SSL connection factory object + * + * DEFAULT connection SSLAVA_CONNECTION will be used if + * type specified is incorrect. + * + * @param type supported SSL connection type: + * SSLAVA_CONNECTION, SSL_CONNECTION + */ + public SSLConnectionFactory(String type) { + if ((!type.equals(JSS_CONNECTION))&&(!type.equals(SSL_CONNECTION)) ) { + System.out.println("SSL Connection Type not found default is used"); + mType = JSS_CONNECTION; + } else { + mType = type; + } + } + + /*========================================================== + * public methods + *==========================================================*/ + + /** + * Creates connection using the host and port + */ + public IConnection create(String host, int port) + throws IOException, UnknownHostException { + + if (mType.equals(JSS_CONNECTION)) + return new JSSConnection(host, port); + return new JSSConnection(host, port); + //return new SSLConnection(host, port); + } + +} |