//*************************************************************************** // (c) Copyright IBM Corp. 2007 All rights reserved. // // The following sample of source code ("Sample") is owned by International // Business Machines Corporation or one of its subsidiaries ("IBM") and is // copyrighted and licensed, not sold. You may use, copy, modify, and // distribute the Sample in any form without payment to IBM, for the purpose of // assisting you in the development of your applications. // // The Sample code is provided to you on an "AS IS" basis, without warranty of // any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR // IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do // not allow for the exclusion or limitation of implied warranties, so the above // limitations or exclusions may not apply to you. IBM shall not be liable for // any damages you suffer as a result of using, copying, modifying or // distributing the Sample, even if IBM has been advised of the possibility of // such damages. //*************************************************************************** // // SOURCE FILE NAME: JCCKerberosPlugin.java // // This set of sample shows: // // 1. How to implement a JCC plugin which does Kerberos authentication // 2. How to use this sample plugin to get a Connection. // // In order to implement a JCC plugin, user needs to extend com.ibm.db2.jcc.DB2JCCPlugin // and implement the following method: // public abstract byte[] getTicket (String username, String password, // byte[] returnedToken) throws org.ietf.jgss.GSSException; // // Plugin users also need to implement some JGSS APIs. The following is a list of JGSS APIs // required for Java Security Plugin interface. // // GSSContext.requestMutualAuth(boolean state) // GSSContext.getMutualAuthState() // GSSContext.requestCredDeleg(boolean state) // GSSContext.getCredDelegState() // GSSContext.initSecContext (byte[] inputBuf, int offset, int len) // GSSContext.dispose() // GSSCredential.dispose() // // The APIs should follow the Generic Security Service Application Program Interface, // Version 2 (IETF RFC2743) and Generic Security Service // API Version 2: Java-Bindings (IETF RFC2853) specifications. // For Kerberos, the implementations are already available through the default instance // of the GSSManager class. // // This set of sample implements a plugin that does kerberos authentication. // It uses Kerberos implementation in jgss package // It corresponds to the c sample plugin IBMkrb5 in sqllib\samples\securtiy\plugins\ // // This set of sample contains the following 3 files: // // JCCKerberosPluginTest.java // This file uses sample plugin JCCKerberosPlugin to get a Connection from DB2 server // // JCCKerberosPlugin.java // This file implements the sample JCCKerberosPlugin. // // JCCSimpleGSSException.java // This file is used by JCCKerberosPlugin for Exception handling // // How to run this JCCKerberosPlugin sample: // // Compile the above 3 files using: javac *.java // Run JCCKerberosPluginTest using // java JCCKerberosPluginTest server port dbname userid password serverPrincipalName // // Note: To run this sample, server side plugin IBMkrb5 needs to be installed in // the server plug-in directory on the server. Database manager configuration // parameters SRVCON_GSS_PLUGIN_LIST and SRVCON_AUTH need to set correctly // // None //*************************************************************************** // // For more information on the sample programs, see the README file. // // For information on developing Java applications see the Developing Java Applications book. // // For information on using SQL statements, see the SQL Reference. // // For the latest information on programming, compiling, and running DB2 // applications, visit the DB2 Information Center at // http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/index.jsp //**************************************************************************/ import org.ietf.jgss.*; public class JCCKerberosPlugin extends com.ibm.db2.jcc.DB2JCCPlugin implements java.security.PrivilegedExceptionAction { private org.ietf.jgss.GSSManager manager_ = org.ietf.jgss.GSSManager.getInstance(); private org.ietf.jgss.GSSName serverGSSName_ ; private byte[] ticket = null; private byte[] returnedToken_ = null; public JCCKerberosPlugin() {} public JCCKerberosPlugin ( String serverPrincipalName) { serverPrincipalName_ = serverPrincipalName; } /** * Convert text service principal name into the GSS-API internal format for use with the other APIs * @parm serverPrincipalName String * @return GSSName server principal name in GSSName format * @throws GSSException if an error occurs. */ public org.ietf.jgss.GSSName processServerPrincipalName(String serverPrincipalName) throws org.ietf.jgss.GSSException { org.ietf.jgss.Oid krb5Oid = new org.ietf.jgss.Oid("1.2.840.113554.1.2.2"); if (serverPrincipalName != null) return manager_.createName (serverPrincipalName_, null, krb5Oid); else throw new JCCSimpleGSSException(0,"plugin bad principal name."); } /** * This method will generate the security context information for the username/password pair. * The security context information will be used to get the connection * @param username String * @param password String * @param returnedByte byte[] the token returned by DB2 server * @throws SQLException if an error occurs. * @return byte[] the security context information for this username/password pair */ public byte[] getTicket(String username, String password, byte[] returnedByte) throws java.sql.SQLException { returnedToken_ = returnedByte; if (username == null) { setUseSubjectCredsOnly(false); try{ getTicketX(); } catch(org.ietf.jgss.GSSException e) { throw new java.sql.SQLException(e.getMessage()); } } else { setUseSubjectCredsOnly (true); try { com.ibm.db2.jcc.am.Krb5JAASCallbackHandler handler = new com.ibm.db2.jcc.am.Krb5JAASCallbackHandler(); handler.setUser(username); handler.setPassword(password); javax.security.auth.login.LoginContext loginCtxt = new javax.security.auth.login.LoginContext("JaasClient", handler); loginCtxt.login(); javax.security.auth.Subject subject = loginCtxt.getSubject(); javax.security.auth.Subject.doAsPrivileged(subject, this, null); } catch (javax.security.auth.login.LoginException e) { throw new java.sql.SQLException("javax.security.auth.login.LoginException happened"); } catch (java.security.PrivilegedActionException e) { throw new java.sql.SQLException("java.security.PrivilegedActionException happened."); } } return ticket; } /** * This method will generate the security context information. * It is called by getTicket(String username, String password, byte[] returnedByte) * @throws GSSException if an error occurs */ public void getTicketX() throws org.ietf.jgss.GSSException { if(returnedToken_ == null) { /* * Create a GSSName out of the server's name. */ serverGSSName_ = processServerPrincipalName(serverPrincipalName_); /* * Create a GSSContext for mutual authentication with the * server. */ org.ietf.jgss.Oid defaultMech = null; context_ = manager_.createContext(serverGSSName_, defaultMech, gssCredential_, org.ietf.jgss.GSSContext.INDEFINITE_LIFETIME); context_.requestMutualAuth(true); // Mutual authentication returnedToken_ = new byte[0]; } int tokenLength = 0; if (returnedToken_ != null) tokenLength = returnedToken_.length; ticket = context_.initSecContext(returnedToken_, 0, tokenLength); } /** * It sets the JAVA variable javax.security.auth.useSubjectCredsOnly * to useSubjectCredsOnly * If useSubjectCredsOnly is false, JGSS will not acquire credentials * through JAAS and Kinit will be used to get the initial credentials * If useSubjectCredsOnly is true, JGSS will acquire credentials * through JAAS * @param useSubjectCredsOnly boolean */ public void setUseSubjectCredsOnly (boolean useSubjectCredsOnly) { final String subjectOnly = useSubjectCredsOnly ? "true" : "false"; final String property = "javax.security.auth.useSubjectCredsOnly"; String temp = (String) java.security.AccessController.doPrivileged ( new sun.security.action.GetPropertyAction (property)); // Property not set. Set it to the specified value. if(temp == null) java.security.AccessController.doPrivileged ( new java.security.PrivilegedAction() { public Object run() { System.setProperty (property, subjectOnly); return null; } } ); } public Object run () throws org.ietf.jgss.GSSException { getTicketX(); return null; } }