package com.perforce.sso.client; /* Copyright (c) Perforce Software, Inc., 2011-2012. All rights reserved Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PERFORCE SOFTWARE, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. User contributed content on the Perforce Public Depot is not supported by Perforce, although it may be supported by its author. This applies to all contributions even those submitted by Perforce employees. */ import java.io.FileWriter; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import javax.security.auth.Subject; import javax.security.auth.login.LoginContext; import org.apache.commons.codec.binary.Base64; import org.ietf.jgss.GSSContext; import org.ietf.jgss.GSSCredential; import org.ietf.jgss.GSSManager; import org.ietf.jgss.GSSName; import org.ietf.jgss.Oid; import org.apache.log4j.*; import org.apache.log4j.varia.NullAppender; /** * The client-side SSO trigger. Responsible for * obtaining a Kerberos ticket-granting ticket. */ public class KerbClient { /** * logger */ private static Logger logger = null; /** * keyword for no log file */ private static final String NO_LOG = "NONE"; /** * keyword for appending to log file */ private static final String LOG_APPEND = "true"; /** * Expected arguments: * <ul> * <li>log file name, set to <code>NONE</code> for no logging * <li>append existing log: can be <code>true</code> or <code>false</code> * <li>Kerberos/AD realm * <li>Kerberos/AD domain controller * <li>Login configuration file * <li>Service name * </ul> * @param args Command line arguments */ public static void main(String[] args) { // check for log arguments if(args.length < 2) { System.out.println("Required logging argument missing"); System.exit(1); } // no log args try { // start logger String logFileName = args[0]; String appendLog = args[1]; if(logFileName.equals(NO_LOG)) { BasicConfigurator.configure(new NullAppender()); } // no logging else { FileAppender fileAppender = new FileAppender(new PatternLayout(PatternLayout.DEFAULT_CONVERSION_PATTERN), logFileName, appendLog.equals(LOG_APPEND)); BasicConfigurator.configure(fileAppender); } // use file log logger = Logger.getLogger(KerbClient.class.getName()); // verify rest of command line if(args.length != 6) { logger.error("Invalid command line: got " + args.length + " arguments"); System.out.println("Invalid command line: got " + args.length + " arguments"); System.exit(1); } // invalid command line String realm = requiredArg(args[2], "Realm"); String domainController = requiredArg(args[3], "Domain controller"); String loginConfFile = requiredArg(args[4], "Login configuration file"); String serviceName = requiredArg(args[5], "Perforce service name"); // basic Kerberos properties System.setProperty("java.security.krb5.realm", realm); System.setProperty("java.security.krb5.kdc", domainController); System.setProperty("java.security.auth.login.config", loginConfFile); logger.debug("Set Kerberos properties"); // create a LoginContext based on the entry in the login.conf file LoginContext lc = new LoginContext("SignedOnUserLoginContext"); // login (effectively populating the Subject) lc.login(); logger.info("Authenticated as current user"); // get the Subject that represents the signed-on user Subject clientSubject = lc.getSubject(); // get service ticket byte[] serviceTicket = (byte[]) Subject.doAs(clientSubject, new ServiceTicketGenerator(clientSubject, serviceName)); logger.info("Got encoded service ticket"); // encode ticket Base64 b64 = new Base64(); String ticket = b64.encodeAsString(serviceTicket); logger.debug("Service ticket: " + ticket); // print to stdout System.out.println(ticket); logger.debug("Wrote ticket"); System.exit(0); } // try catch(Exception e) { if(null != logger) { logger.error(e.getMessage(), e); System.out.println(e.getMessage()); } // can use logger else { System.out.println("Unexpected error, probably while starting logging system: " + e.getMessage()); } // no logger System.exit(1); } // catch } // main /** * verifies that a required argument is present */ private static String requiredArg(String input, String paramName) { if(null == input || input.length() < 1) { logger.error(paramName + " is required argument to this program"); System.out.println(paramName + " is required argument to this program"); System.exit(1); } // no input return input; } // requiredArg } // class KerbClient /** * Responsible for obtaining the service ticket */ final class ServiceTicketGenerator implements PrivilegedExceptionAction< byte[] > { /** * the current user */ private final Subject subject; /** * service name */ private final String svcName; /** * logger */ private final Logger logger; /** * ctor - start logger */ public ServiceTicketGenerator(Subject s, String svcName) { this.subject = s; this.svcName = svcName; this.logger = Logger.getLogger(ServiceTicketGenerator.class.getName()); } // ctor public byte[] run() throws Exception { try { // GSSAPI is generic, but if you give it the following Object ID, // it will create Kerberos 5 service tickets Oid kerberos5Oid = new Oid("1.2.840.113554.1.2.2"); // create a GSSManager, which will do the work GSSManager gssManager = GSSManager.getInstance(); // tell the GSSManager the Kerberos name of the client and service (substitute your appropriate names here) String theClientName = subject.getPrincipals().iterator().next().getName(); this.logger.info("Authenticating as: " + theClientName); GSSName clientName = gssManager.createName(theClientName, GSSName.NT_USER_NAME); GSSName serviceName = gssManager.createName(this.svcName, null); // get the client's credentials. note that this run() method was called by Subject.doAs(), // so the client's credentials (Kerberos TGT or Ticket-Granting Ticket) are already available in the Subject GSSCredential clientCredentials = gssManager.createCredential(clientName, 8*60*60, kerberos5Oid, GSSCredential.INITIATE_ONLY); this.logger.debug("Created client credentials"); // create a security context between the client and the service GSSContext gssContext = gssManager.createContext(serviceName, kerberos5Oid, clientCredentials, GSSContext.DEFAULT_LIFETIME); this.logger.debug("Created service context"); // initialize the security context // this operation will cause a Kerberos request of Active Directory, // to create a service ticket for the client to use the service byte[] serviceTicket = gssContext.initSecContext(new byte[0], 0, 0); logger.info("Created service ticket"); gssContext.dispose(); // return the Kerberos service ticket as an array of encrypted bytes return serviceTicket; } // try catch (Exception ex) { throw new PrivilegedActionException(ex); } // catch } // run } // class ServiceTicketGenerator
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 22152 | Randall Fong |
copying files from //guest/perforce_software/sso-p4/java/... to //guest/perforce_software/sso-p4/main/... |
||
//guest/perforce_software/sso-p4/java/KerbClient/src/com/perforce/sso/client/KerbClient.java | |||||
#1 | 12125 | alan_petersen | initial submit of sso-p4 |