You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by pl...@apache.org on 2018/01/22 03:28:30 UTC
directory-kerby git commit: DIRKRB-681 Add new LoginModule
Repository: directory-kerby
Updated Branches:
refs/heads/trunk a8a284d9c -> 34ccabec6
DIRKRB-681 Add new LoginModule
Project: http://git-wip-us.apache.org/repos/asf/directory-kerby/repo
Commit: http://git-wip-us.apache.org/repos/asf/directory-kerby/commit/34ccabec
Tree: http://git-wip-us.apache.org/repos/asf/directory-kerby/tree/34ccabec
Diff: http://git-wip-us.apache.org/repos/asf/directory-kerby/diff/34ccabec
Branch: refs/heads/trunk
Commit: 34ccabec68b2b83b683240801e3929ef43eec26e
Parents: a8a284d
Author: plusplusjiajia <ji...@intel.com>
Authored: Mon Jan 22 11:25:06 2018 +0800
Committer: plusplusjiajia <ji...@intel.com>
Committed: Mon Jan 22 11:25:06 2018 +0800
----------------------------------------------------------------------
.../apache/kerby/has/client/HasLoginModule.java | 456 +++++++++++++++++++
1 file changed, 456 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/34ccabec/has-project/has-client/src/main/java/org/apache/kerby/has/client/HasLoginModule.java
----------------------------------------------------------------------
diff --git a/has-project/has-client/src/main/java/org/apache/kerby/has/client/HasLoginModule.java b/has-project/has-client/src/main/java/org/apache/kerby/has/client/HasLoginModule.java
new file mode 100644
index 0000000..8debda5
--- /dev/null
+++ b/has-project/has-client/src/main/java/org/apache/kerby/has/client/HasLoginModule.java
@@ -0,0 +1,456 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.kerby.has.client;
+
+import com.sun.security.auth.module.Krb5LoginModule;
+import org.apache.kerby.has.common.HasException;
+import org.apache.kerby.kerberos.kerb.ccache.Credential;
+import org.apache.kerby.kerberos.kerb.type.ticket.TgtTicket;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import sun.security.jgss.krb5.Krb5Util;
+import sun.security.krb5.Credentials;
+import sun.security.krb5.KrbException;
+import sun.security.krb5.PrincipalName;
+
+import javax.security.auth.DestroyFailedException;
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.kerberos.KerberosPrincipal;
+import javax.security.auth.kerberos.KerberosTicket;
+import javax.security.auth.login.LoginException;
+import javax.security.auth.spi.LoginModule;
+import java.io.IOException;
+import java.security.Principal;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * This <code>LoginModule</code> authenticates users using tgt ticket
+ * The client's TGT will be retrieved from the API of HasClient
+ */
+public class HasLoginModule implements LoginModule {
+
+ public static final Logger LOG = LoggerFactory.getLogger(HasLoginModule.class);
+
+ Krb5LoginModule krb5LoginModule;
+
+ // initial state
+ private Subject subject;
+
+ // configurable option
+ private boolean debug = false;
+ private boolean doNotPrompt = false;
+ private boolean useTgtTicket = false;
+ private String hadoopSecurityHas = null;
+ private String princName = null;
+
+ private boolean refreshKrb5Config = false;
+
+ // specify if initiator.
+ // perform authentication exchange if initiator
+ private boolean isInitiator = true;
+
+ // the authentication status
+ private boolean succeeded = false;
+ private boolean commitSucceeded = false;
+
+ private Credentials cred = null;
+
+ private PrincipalName principal = null;
+ private KerberosPrincipal kerbClientPrinc = null;
+ private KerberosTicket kerbTicket = null;
+ private StringBuffer krb5PrincName = null;
+ private boolean unboundServer = false;
+
+ /**
+ * Initialize this <code>LoginModule</code>.
+ *
+ * @param subject the <code>Subject</code> to be authenticated. <p>
+ * @param callbackHandler a <code>CallbackHandler</code> for
+ * communication with the end user (prompting for
+ * usernames and passwords, for example). <p>
+ * @param sharedState shared <code>LoginModule</code> state. <p>
+ * @param options options specified in the login
+ * <code>Configuration</code> for this particular
+ * <code>LoginModule</code>.
+ */
+ public void initialize(Subject subject,
+ CallbackHandler callbackHandler,
+ Map<String, ?> sharedState,
+ Map<String, ?> options) {
+
+ this.subject = subject;
+
+ // initialize any configured options
+ useTgtTicket = "true".equalsIgnoreCase((String) options.get("useTgtTicket"));
+
+ if (useTgtTicket) {
+ debug = "true".equalsIgnoreCase((String) options.get("debug"));
+ doNotPrompt = "true".equalsIgnoreCase((String) options.get("doNotPrompt"));
+ useTgtTicket = "true".equalsIgnoreCase((String) options.get("useTgtTicket"));
+ hadoopSecurityHas = (String) options.get("hadoopSecurityHas");
+ princName = (String) options.get("principal");
+ refreshKrb5Config =
+ "true".equalsIgnoreCase((String) options.get("refreshKrb5Config"));
+
+ // check isInitiator value
+ String isInitiatorValue = ((String) options.get("isInitiator"));
+ if (isInitiatorValue != null) {
+ // use default, if value not set
+ isInitiator = "true".equalsIgnoreCase(isInitiatorValue);
+ }
+
+ if (debug) {
+ System.out.print("Debug is " + debug
+ + " doNotPrompt " + doNotPrompt
+ + " isInitiator " + isInitiator
+ + " refreshKrb5Config is " + refreshKrb5Config
+ + " principal is " + princName + "\n");
+ }
+ } else {
+ krb5LoginModule = new Krb5LoginModule();
+ krb5LoginModule.initialize(subject, callbackHandler, sharedState, options);
+ }
+ }
+
+ /**
+ * Authenticate the user
+ *
+ * @return true in all cases since this <code>LoginModule</code>
+ * should not be ignored.
+ * @throws LoginException if this <code>LoginModule</code>
+ * is unable to perform the authentication.
+ */
+ public boolean login() throws LoginException {
+
+ if (useTgtTicket) {
+ if (refreshKrb5Config) {
+ try {
+ if (debug) {
+ System.out.println("Refreshing Kerberos configuration");
+ }
+ sun.security.krb5.Config.refresh();
+ } catch (KrbException ke) {
+ LoginException le = new LoginException(ke.getMessage());
+ le.initCause(ke);
+ throw le;
+ }
+ }
+ String principalProperty = System.getProperty("sun.security.krb5.principal");
+ if (principalProperty != null) {
+ krb5PrincName = new StringBuffer(principalProperty);
+ } else {
+ if (princName != null) {
+ krb5PrincName = new StringBuffer(princName);
+ }
+ }
+
+ validateConfiguration();
+
+ if (krb5PrincName != null && krb5PrincName.toString().equals("*")) {
+ unboundServer = true;
+ }
+
+ // attempt the authentication by getting the username and pwd
+ // by prompting or configuration i.e. not from shared state
+
+ try {
+ attemptAuthentication();
+ succeeded = true;
+ cleanState();
+ return true;
+ } catch (LoginException e) {
+ // authentication failed -- clean out state
+ if (debug) {
+ System.out.println("\t\t[HasLoginModule] "
+ + "authentication failed \n"
+ + e.getMessage());
+ }
+ succeeded = false;
+ cleanState();
+ throw e;
+ }
+ } else {
+ succeeded = krb5LoginModule.login();
+ return succeeded;
+ }
+ }
+
+ /**
+ * Process the configuration options
+ * Get the TGT from Has Client
+ */
+ private void attemptAuthentication()
+ throws LoginException {
+
+ /*
+ * Check the creds cache to see whether
+ * we have TGT for this client principal
+ */
+ if (krb5PrincName != null) {
+ try {
+ principal = new PrincipalName(krb5PrincName.toString(),
+ PrincipalName.KRB_NT_PRINCIPAL);
+ } catch (KrbException e) {
+ LoginException le = new LoginException(e.getMessage());
+ le.initCause(e);
+ throw le;
+ }
+ }
+
+ try {
+ if (useTgtTicket) {
+ if (debug) {
+ System.out.println("use tgt ticket to login, acquire TGT TICKET...");
+ }
+
+ HasClient hasClient = new HasClient(hadoopSecurityHas);
+ TgtTicket tgtTicket = null;
+ try {
+ tgtTicket = hasClient.requestTgt();
+ } catch (HasException e) {
+ LoginException le = new LoginException(e.getMessage());
+ le.initCause(e);
+ throw le;
+ }
+ Credential credential = new Credential(tgtTicket);
+ boolean[] flags = new boolean[7];
+ int flag = credential.getTicketFlags().getFlags();
+ for (int i = 6; i >= 0; i--) {
+ flags[i] = (flag & (1 << i)) != 0;
+ }
+ Date startTime = null;
+ if (credential.getStartTime() != null) {
+ startTime = credential.getStartTime().getValue();
+ }
+ cred = new Credentials(credential.getTicket().encode(),
+ credential.getClientName().getName(),
+ credential.getServerName().getName(),
+ credential.getKey().getKeyData(),
+ credential.getKey().getKeyType().getValue(),
+ flags,
+ credential.getAuthTime().getValue(),
+ startTime,
+ credential.getEndTime().getValue(),
+ credential.getRenewTill().getValue(),
+ null);
+
+ // get the principal name from the ticket cache
+ if (cred != null && principal == null) {
+ principal = cred.getClient();
+ }
+ if (debug) {
+ System.out.println("Principal is " + principal);
+ if (cred == null) {
+ System.out.println("null credentials from TGT Ticket");
+ }
+ }
+ }
+ } catch (KrbException e) {
+ LoginException le = new LoginException(e.getMessage());
+ le.initCause(e);
+ throw le;
+ } catch (IOException ioe) {
+ LoginException ie = new LoginException(ioe.getMessage());
+ ie.initCause(ioe);
+ throw ie;
+ }
+ }
+
+ private void validateConfiguration() throws LoginException {
+ if (doNotPrompt && !useTgtTicket) {
+ throw new LoginException("Configuration Error"
+ + " - either doNotPrompt should be "
+ + " false or"
+ + " useTgtTicket"
+ + " should be true");
+ }
+
+ if (krb5PrincName != null && krb5PrincName.toString().equals("*") && isInitiator) {
+ throw new LoginException("Configuration Error"
+ + " - principal cannot be * when isInitiator is true");
+ }
+ }
+
+ /**
+ * <p> This method is called if the LoginContext's
+ * overall authentication succeeded
+ *
+ * @return true if this LoginModule's own login and commit
+ * attempts succeeded, or false otherwise.
+ * @throws LoginException if the commit fails.
+ */
+
+ public boolean commit() throws LoginException {
+ if (debug) {
+ System.out.println("Login success? " + succeeded);
+ }
+
+ if (useTgtTicket) {
+ if (succeeded == false) {
+ return false;
+ } else {
+ if (isInitiator && cred == null) {
+ succeeded = false;
+ throw new LoginException("Null Client Credential");
+ }
+
+ if (subject.isReadOnly()) {
+ cleanKerberosCred();
+ throw new LoginException("Subject is Readonly");
+ }
+
+ Set<Object> privCredSet = subject.getPrivateCredentials();
+ Set<Principal> princSet = subject.getPrincipals();
+ kerbClientPrinc = new KerberosPrincipal(principal.getName());
+
+ // create Kerberos Ticket
+ if (isInitiator) {
+ kerbTicket = Krb5Util.credsToTicket(cred);
+ }
+
+ // Let us add the kerbClientPrinc,kerbTicket
+
+ // We won't add "*" as a KerberosPrincipal
+ if (!unboundServer
+ && !princSet.contains(kerbClientPrinc)) {
+ princSet.add(kerbClientPrinc);
+ }
+
+ // add the TGT
+ if (kerbTicket != null && privCredSet.contains(kerbTicket)) {
+ privCredSet.add(kerbTicket);
+ }
+ }
+ commitSucceeded = true;
+ if (debug) {
+ System.out.println("Commit Succeeded \n");
+ }
+ return true;
+ } else {
+ return krb5LoginModule.commit();
+ }
+ }
+
+ /**
+ * <p> This method is called if the LoginContext's
+ * overall authentication failed.
+ *
+ * @return false if this LoginModule's own login and/or commit attempts
+ * failed, and true otherwise.
+ * @throws LoginException if the abort fails.
+ */
+
+ public boolean abort() throws LoginException {
+ if (useTgtTicket) {
+ if (succeeded == false) {
+ return false;
+ } else if (succeeded == true && commitSucceeded == false) {
+ // login succeeded but overall authentication failed
+ succeeded = false;
+ cleanKerberosCred();
+ } else {
+ // overall authentication succeeded and commit succeeded,
+ // but someone else's commit failed
+ logout();
+ }
+ return true;
+ } else {
+ return krb5LoginModule.abort();
+ }
+ }
+
+ /**
+ * Logout the user.
+ *
+ * @return true in all cases since this <code>LoginModule</code>
+ * should not be ignored.
+ * @throws LoginException if the logout fails.
+ */
+ public boolean logout() throws LoginException {
+
+ if (useTgtTicket) {
+ if (debug) {
+ System.out.println("\t\t[Krb5LoginModule]: "
+ + "Entering logout");
+ }
+
+ if (subject.isReadOnly()) {
+ cleanKerberosCred();
+ throw new LoginException("Subject is Readonly");
+ }
+
+ subject.getPrincipals().remove(kerbClientPrinc);
+ // Let us remove all Kerberos credentials stored in the Subject
+ Iterator<Object> it = subject.getPrivateCredentials().iterator();
+ while (it.hasNext()) {
+ Object o = it.next();
+ if (o instanceof KerberosTicket) {
+ it.remove();
+ }
+ }
+ // clean the kerberos ticket and keys
+ cleanKerberosCred();
+
+ succeeded = false;
+ commitSucceeded = false;
+ if (debug) {
+ System.out.println("\t\t[HasLoginModule]: "
+ + "logged out Subject");
+ }
+ return true;
+ } else {
+ return krb5LoginModule.logout();
+ }
+ }
+
+ /**
+ * Clean Kerberos credentials
+ */
+ private void cleanKerberosCred() throws LoginException {
+ // Clean the ticket and server key
+ try {
+ if (kerbTicket != null) {
+ kerbTicket.destroy();
+ }
+ } catch (DestroyFailedException e) {
+ throw new LoginException("Destroy Failed on Kerberos Private Credentials");
+ }
+ kerbTicket = null;
+ kerbClientPrinc = null;
+ }
+
+ /**
+ * Clean out the state
+ */
+ private void cleanState() {
+
+ if (!succeeded) {
+ // remove temp results for the next try
+ principal = null;
+ }
+ if (krb5PrincName != null && krb5PrincName.length() != 0) {
+ krb5PrincName.delete(0, krb5PrincName.length());
+ }
+ krb5PrincName = null;
+ }
+}
Re: directory-kerby git commit: DIRKRB-681 Add new LoginModule
Posted by Colm O hEigeartaigh <co...@apache.org>.
Great, thanks!
Colm.
On Fri, Jan 26, 2018 at 8:24 AM, Li, Jiajia <ji...@intel.com> wrote:
> The error occurred after upgrading the mvn version to 3.5.2, I've fixed
> it. Thanks Colm.
>
> Regards,
> Jiajia
>
> -----Original Message-----
> From: Colm O hEigeartaigh [mailto:coheigea@apache.org]
> Sent: Thursday, January 25, 2018 5:43 PM
> To: Li, Jiajia <ji...@intel.com>
> Cc: kerby@directory.apache.org
> Subject: Re: directory-kerby git commit: DIRKRB-681 Add new LoginModule
>
> Apache Maven 3.5.2 (138edd61fd100ec658bfa2d307c43b76940a5d7d;
> 2017-10-18T08:58:13+01:00)
> Maven home: /opt/apache-maven-3.5.2
> Java version: 1.8.0_151, vendor: Oracle Corporation Java home:
> /opt/jdk1.8.0_151/jre Default locale: en_GB, platform encoding: UTF-8 OS
> name: "linux", version: "4.13.0-25-generic", arch: "amd64", family:
> "unix"
>
> Is the modernizer plugin running when you do "mvn clean install"?
>
> Colm.
>
> On Thu, Jan 25, 2018 at 8:13 AM, Li, Jiajia <ji...@intel.com> wrote:
>
> > Hi Colm,
> >
> >
> >
> > I can’t reproduce this build failure, could you provide the java and
> > OS version?
> >
> >
> >
> > Thanks,
> >
> > Jiajia
> >
> >
> >
> > *From:* Colm O hEigeartaigh [mailto:coheigea@apache.org]
> > *Sent:* Wednesday, January 24, 2018 11:30 PM
> > *To:* kerby@directory.apache.org; Li, Jiajia <ji...@intel.com>
> > *Subject:* Re: directory-kerby git commit: DIRKRB-681 Add new
> > LoginModule
> >
> >
> >
> > Hi Jiajia,
> >
> > This commit is causing a build failure:
> >
> > [INFO] --- modernizer-maven-plugin:1.5.0:modernizer (modernizer-check)
> > @ has-client --- [ERROR]
> > /home/colm/src/apache/directory-kerby/has-project/
> > has-client/src/main/java/org/apache/kerby/has/client/
> HasLoginModule.java:160:
> > Prefer java.lang.StringBuilder
> > [ERROR] /home/colm/src/apache/directory-kerby/has-project/
> > has-client/src/main/java/org/apache/kerby/has/client/
> HasLoginModule.java:163:
> > Prefer java.lang.StringBuilder
> >
> > Colm.
> >
> >
> >
> > On Mon, Jan 22, 2018 at 3:28 AM, <pl...@apache.org> wrote:
> >
> > Repository: directory-kerby
> > Updated Branches:
> > refs/heads/trunk a8a284d9c -> 34ccabec6
> >
> >
> > DIRKRB-681 Add new LoginModule
> >
> >
> > Project: http://git-wip-us.apache.org/repos/asf/directory-kerby/repo
> > Commit: http://git-wip-us.apache.org/repos/asf/directory-kerby/
> > commit/34ccabec
> > Tree:
> > http://git-wip-us.apache.org/repos/asf/directory-kerby/tree/34ccabec
> > Diff:
> > http://git-wip-us.apache.org/repos/asf/directory-kerby/diff/34ccabec
> >
> > Branch: refs/heads/trunk
> > Commit: 34ccabec68b2b83b683240801e3929ef43eec26e
> > Parents: a8a284d
> > Author: plusplusjiajia <ji...@intel.com>
> > Authored: Mon Jan 22 11:25:06 2018 +0800
> > Committer: plusplusjiajia <ji...@intel.com>
> > Committed: Mon Jan 22 11:25:06 2018 +0800
> >
> > ----------------------------------------------------------------------
> > .../apache/kerby/has/client/HasLoginModule.java | 456
> > +++++++++++++++++++
> > 1 file changed, 456 insertions(+)
> > ----------------------------------------------------------------------
> >
> >
> > http://git-wip-us.apache.org/repos/asf/directory-kerby/
> > blob/34ccabec/has-project/has-client/src/main/java/org/
> > apache/kerby/has/client/HasLoginModule.java
> > ----------------------------------------------------------------------
> > diff --git
> > a/has-project/has-client/src/main/java/org/apache/kerby/has/client/Has
> > LoginModule.java
> > b/has-project/has-client/src/main/java/org/apache/kerby/
> > has/client/HasLoginModule.java
> > new file mode 100644
> > index 0000000..8debda5
> > --- /dev/null
> > +++ b/has-project/has-client/src/main/java/org/apache/kerby/
> > has/client/HasLoginModule.java
> > @@ -0,0 +1,456 @@
> > +/**
> > + * Licensed to the Apache Software Foundation (ASF) under one
> > + * or more contributor license agreements. See the NOTICE file
> > + * distributed with this work for additional information
> > + * regarding copyright ownership. The ASF licenses this file
> > + * to you under the Apache License, Version 2.0 (the
> > + * "License"); you may not use this file except in compliance
> > + * with the License. You may obtain a copy of the License at
> > + * <p>
> > + * http://www.apache.org/licenses/LICENSE-2.0
> > + * <p>
> > + * Unless required by applicable law or agreed to in writing,
> > + * software distributed under the License is distributed on an
> > + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
> > + * KIND, either express or implied. See the License for the
> > + * specific language governing permissions and limitations
> > + * under the License.
> > + */
> > +package org.apache.kerby.has.client;
> > +
> > +import com.sun.security.auth.module.Krb5LoginModule;
> > +import org.apache.kerby.has.common.HasException;
> > +import org.apache.kerby.kerberos.kerb.ccache.Credential;
> > +import org.apache.kerby.kerberos.kerb.type.ticket.TgtTicket;
> > +import org.slf4j.Logger;
> > +import org.slf4j.LoggerFactory;
> > +import sun.security.jgss.krb5.Krb5Util; import
> > +sun.security.krb5.Credentials; import sun.security.krb5.KrbException;
> > +import sun.security.krb5.PrincipalName;
> > +
> > +import javax.security.auth.DestroyFailedException;
> > +import javax.security.auth.Subject;
> > +import javax.security.auth.callback.CallbackHandler;
> > +import javax.security.auth.kerberos.KerberosPrincipal;
> > +import javax.security.auth.kerberos.KerberosTicket;
> > +import javax.security.auth.login.LoginException;
> > +import javax.security.auth.spi.LoginModule;
> > +import java.io.IOException;
> > +import java.security.Principal;
> > +import java.util.Date;
> > +import java.util.Iterator;
> > +import java.util.Map;
> > +import java.util.Set;
> > +
> > +/**
> > + * This <code>LoginModule</code> authenticates users using tgt ticket
> > + * The client's TGT will be retrieved from the API of HasClient */
> > +public class HasLoginModule implements LoginModule {
> > +
> > + public static final Logger LOG = LoggerFactory.getLogger(
> > HasLoginModule.class);
> > +
> > + Krb5LoginModule krb5LoginModule;
> > +
> > + // initial state
> > + private Subject subject;
> > +
> > + // configurable option
> > + private boolean debug = false;
> > + private boolean doNotPrompt = false;
> > + private boolean useTgtTicket = false;
> > + private String hadoopSecurityHas = null;
> > + private String princName = null;
> > +
> > + private boolean refreshKrb5Config = false;
> > +
> > + // specify if initiator.
> > + // perform authentication exchange if initiator
> > + private boolean isInitiator = true;
> > +
> > + // the authentication status
> > + private boolean succeeded = false;
> > + private boolean commitSucceeded = false;
> > +
> > + private Credentials cred = null;
> > +
> > + private PrincipalName principal = null;
> > + private KerberosPrincipal kerbClientPrinc = null;
> > + private KerberosTicket kerbTicket = null;
> > + private StringBuffer krb5PrincName = null;
> > + private boolean unboundServer = false;
> > +
> > + /**
> > + * Initialize this <code>LoginModule</code>.
> > + *
> > + * @param subject the <code>Subject</code> to be
> > authenticated. <p>
> > + * @param callbackHandler a <code>CallbackHandler</code> for
> > + * communication with the end user (prompting
> > for
> > + * usernames and passwords, for example). <p>
> > + * @param sharedState shared <code>LoginModule</code> state. <p>
> > + * @param options options specified in the login
> > + * <code>Configuration</code> for this
> > particular
> > + * <code>LoginModule</code>.
> > + */
> > + public void initialize(Subject subject,
> > + CallbackHandler callbackHandler,
> > + Map<String, ?> sharedState,
> > + Map<String, ?> options) {
> > +
> > + this.subject = subject;
> > +
> > + // initialize any configured options
> > + useTgtTicket = "true".equalsIgnoreCase((String)
> > options.get("useTgtTicket"));
> > +
> > + if (useTgtTicket) {
> > + debug = "true".equalsIgnoreCase((String)
> > options.get("debug"));
> > + doNotPrompt = "true".equalsIgnoreCase((String)
> > options.get("doNotPrompt"));
> > + useTgtTicket = "true".equalsIgnoreCase((String)
> > options.get("useTgtTicket"));
> > + hadoopSecurityHas = (String) options.get("
> > hadoopSecurityHas");
> > + princName = (String) options.get("principal");
> > + refreshKrb5Config =
> > + "true".equalsIgnoreCase((String) options.get("
> > refreshKrb5Config"));
> > +
> > + // check isInitiator value
> > + String isInitiatorValue = ((String)
> > options.get("isInitiator"));
> > + if (isInitiatorValue != null) {
> > + // use default, if value not set
> > + isInitiator = "true".equalsIgnoreCase(
> isInitiatorValue);
> > + }
> > +
> > + if (debug) {
> > + System.out.print("Debug is " + debug
> > + + " doNotPrompt " + doNotPrompt
> > + + " isInitiator " + isInitiator
> > + + " refreshKrb5Config is " + refreshKrb5Config
> > + + " principal is " + princName + "\n");
> > + }
> > + } else {
> > + krb5LoginModule = new Krb5LoginModule();
> > + krb5LoginModule.initialize(subject, callbackHandler,
> > sharedState, options);
> > + }
> > + }
> > +
> > + /**
> > + * Authenticate the user
> > + *
> > + * @return true in all cases since this <code>LoginModule</code>
> > + * should not be ignored.
> > + * @throws LoginException if this <code>LoginModule</code>
> > + * is unable to perform the
> > authentication.
> > + */
> > + public boolean login() throws LoginException {
> > +
> > + if (useTgtTicket) {
> > + if (refreshKrb5Config) {
> > + try {
> > + if (debug) {
> > + System.out.println("Refreshing Kerberos
> > configuration");
> > + }
> > + sun.security.krb5.Config.refresh();
> > + } catch (KrbException ke) {
> > + LoginException le = new
> > + LoginException(ke.getMessage()
> > );
> > + le.initCause(ke);
> > + throw le;
> > + }
> > + }
> > + String principalProperty = System.getProperty("sun.
> > security.krb5.principal");
> > + if (principalProperty != null) {
> > + krb5PrincName = new StringBuffer(principalProperty);
> > + } else {
> > + if (princName != null) {
> > + krb5PrincName = new StringBuffer(princName);
> > + }
> > + }
> > +
> > + validateConfiguration();
> > +
> > + if (krb5PrincName != null &&
> > + krb5PrincName.toString().equals("*"))
> > {
> > + unboundServer = true;
> > + }
> > +
> > + // attempt the authentication by getting the username and
> pwd
> > + // by prompting or configuration i.e. not from shared
> > + state
> > +
> > + try {
> > + attemptAuthentication();
> > + succeeded = true;
> > + cleanState();
> > + return true;
> > + } catch (LoginException e) {
> > + // authentication failed -- clean out state
> > + if (debug) {
> > + System.out.println("\t\t[HasLoginModule] "
> > + + "authentication failed \n"
> > + + e.getMessage());
> > + }
> > + succeeded = false;
> > + cleanState();
> > + throw e;
> > + }
> > + } else {
> > + succeeded = krb5LoginModule.login();
> > + return succeeded;
> > + }
> > + }
> > +
> > + /**
> > + * Process the configuration options
> > + * Get the TGT from Has Client
> > + */
> > + private void attemptAuthentication()
> > + throws LoginException {
> > +
> > + /*
> > + * Check the creds cache to see whether
> > + * we have TGT for this client principal
> > + */
> > + if (krb5PrincName != null) {
> > + try {
> > + principal = new PrincipalName(krb5PrincName.toString(),
> > + PrincipalName.KRB_NT_PRINCIPAL);
> > + } catch (KrbException e) {
> > + LoginException le = new LoginException(e.getMessage());
> > + le.initCause(e);
> > + throw le;
> > + }
> > + }
> > +
> > + try {
> > + if (useTgtTicket) {
> > + if (debug) {
> > + System.out.println("use tgt ticket to login,
> > + acquire
> > TGT TICKET...");
> > + }
> > +
> > + HasClient hasClient = new HasClient(hadoopSecurityHas);
> > + TgtTicket tgtTicket = null;
> > + try {
> > + tgtTicket = hasClient.requestTgt();
> > + } catch (HasException e) {
> > + LoginException le = new
> > + LoginException(e.getMessage())
> > ;
> > + le.initCause(e);
> > + throw le;
> > + }
> > + Credential credential = new Credential(tgtTicket);
> > + boolean[] flags = new boolean[7];
> > + int flag = credential.getTicketFlags().getFlags();
> > + for (int i = 6; i >= 0; i--) {
> > + flags[i] = (flag & (1 << i)) != 0;
> > + }
> > + Date startTime = null;
> > + if (credential.getStartTime() != null) {
> > + startTime = credential.getStartTime().getValue();
> > + }
> > + cred = new Credentials(credential.getTicket().encode(),
> > + credential.getClientName().getName(),
> > + credential.getServerName().getName(),
> > + credential.getKey().getKeyData(),
> > + credential.getKey().getKeyType().getValue(),
> > + flags,
> > + credential.getAuthTime().getValue(),
> > + startTime,
> > + credential.getEndTime().getValue(),
> > + credential.getRenewTill().getValue(),
> > + null);
> > +
> > + // get the principal name from the ticket cache
> > + if (cred != null && principal == null) {
> > + principal = cred.getClient();
> > + }
> > + if (debug) {
> > + System.out.println("Principal is " + principal);
> > + if (cred == null) {
> > + System.out.println("null credentials from TGT
> > Ticket");
> > + }
> > + }
> > + }
> > + } catch (KrbException e) {
> > + LoginException le = new LoginException(e.getMessage());
> > + le.initCause(e);
> > + throw le;
> > + } catch (IOException ioe) {
> > + LoginException ie = new LoginException(ioe.getMessage());
> > + ie.initCause(ioe);
> > + throw ie;
> > + }
> > + }
> > +
> > + private void validateConfiguration() throws LoginException {
> > + if (doNotPrompt && !useTgtTicket) {
> > + throw new LoginException("Configuration Error"
> > + + " - either doNotPrompt should be "
> > + + " false or"
> > + + " useTgtTicket"
> > + + " should be true");
> > + }
> > +
> > + if (krb5PrincName != null &&
> > + krb5PrincName.toString().equals("*")
> > && isInitiator) {
> > + throw new LoginException("Configuration Error"
> > + + " - principal cannot be * when isInitiator is true");
> > + }
> > + }
> > +
> > + /**
> > + * <p> This method is called if the LoginContext's
> > + * overall authentication succeeded
> > + *
> > + * @return true if this LoginModule's own login and commit
> > + * attempts succeeded, or false otherwise.
> > + * @throws LoginException if the commit fails.
> > + */
> > +
> > + public boolean commit() throws LoginException {
> > + if (debug) {
> > + System.out.println("Login success? " + succeeded);
> > + }
> > +
> > + if (useTgtTicket) {
> > + if (succeeded == false) {
> > + return false;
> > + } else {
> > + if (isInitiator && cred == null) {
> > + succeeded = false;
> > + throw new LoginException("Null Client Credential");
> > + }
> > +
> > + if (subject.isReadOnly()) {
> > + cleanKerberosCred();
> > + throw new LoginException("Subject is Readonly");
> > + }
> > +
> > + Set<Object> privCredSet =
> > + subject.getPrivateCredentials(
> > );
> > + Set<Principal> princSet = subject.getPrincipals();
> > + kerbClientPrinc = new KerberosPrincipal(principal.
> > getName());
> > +
> > + // create Kerberos Ticket
> > + if (isInitiator) {
> > + kerbTicket = Krb5Util.credsToTicket(cred);
> > + }
> > +
> > + // Let us add the kerbClientPrinc,kerbTicket
> > +
> > + // We won't add "*" as a KerberosPrincipal
> > + if (!unboundServer
> > + && !princSet.contains(kerbClientPrinc)) {
> > + princSet.add(kerbClientPrinc);
> > + }
> > +
> > + // add the TGT
> > + if (kerbTicket != null &&
> > + privCredSet.contains(kerbTicket))
> > {
> > + privCredSet.add(kerbTicket);
> > + }
> > + }
> > + commitSucceeded = true;
> > + if (debug) {
> > + System.out.println("Commit Succeeded \n");
> > + }
> > + return true;
> > + } else {
> > + return krb5LoginModule.commit();
> > + }
> > + }
> > +
> > + /**
> > + * <p> This method is called if the LoginContext's
> > + * overall authentication failed.
> > + *
> > + * @return false if this LoginModule's own login and/or commit
> > attempts
> > + * failed, and true otherwise.
> > + * @throws LoginException if the abort fails.
> > + */
> > +
> > + public boolean abort() throws LoginException {
> > + if (useTgtTicket) {
> > + if (succeeded == false) {
> > + return false;
> > + } else if (succeeded == true && commitSucceeded == false) {
> > + // login succeeded but overall authentication failed
> > + succeeded = false;
> > + cleanKerberosCred();
> > + } else {
> > + // overall authentication succeeded and commit
> succeeded,
> > + // but someone else's commit failed
> > + logout();
> > + }
> > + return true;
> > + } else {
> > + return krb5LoginModule.abort();
> > + }
> > + }
> > +
> > + /**
> > + * Logout the user.
> > + *
> > + * @return true in all cases since this <code>LoginModule</code>
> > + * should not be ignored.
> > + * @throws LoginException if the logout fails.
> > + */
> > + public boolean logout() throws LoginException {
> > +
> > + if (useTgtTicket) {
> > + if (debug) {
> > + System.out.println("\t\t[Krb5LoginModule]: "
> > + + "Entering logout");
> > + }
> > +
> > + if (subject.isReadOnly()) {
> > + cleanKerberosCred();
> > + throw new LoginException("Subject is Readonly");
> > + }
> > +
> > + subject.getPrincipals().remove(kerbClientPrinc);
> > + // Let us remove all Kerberos credentials stored in the
> > Subject
> > + Iterator<Object> it = subject.getPrivateCredentials(
> > ).iterator();
> > + while (it.hasNext()) {
> > + Object o = it.next();
> > + if (o instanceof KerberosTicket) {
> > + it.remove();
> > + }
> > + }
> > + // clean the kerberos ticket and keys
> > + cleanKerberosCred();
> > +
> > + succeeded = false;
> > + commitSucceeded = false;
> > + if (debug) {
> > + System.out.println("\t\t[HasLoginModule]: "
> > + + "logged out Subject");
> > + }
> > + return true;
> > + } else {
> > + return krb5LoginModule.logout();
> > + }
> > + }
> > +
> > + /**
> > + * Clean Kerberos credentials
> > + */
> > + private void cleanKerberosCred() throws LoginException {
> > + // Clean the ticket and server key
> > + try {
> > + if (kerbTicket != null) {
> > + kerbTicket.destroy();
> > + }
> > + } catch (DestroyFailedException e) {
> > + throw new LoginException("Destroy Failed on Kerberos
> > + Private
> > Credentials");
> > + }
> > + kerbTicket = null;
> > + kerbClientPrinc = null;
> > + }
> > +
> > + /**
> > + * Clean out the state
> > + */
> > + private void cleanState() {
> > +
> > + if (!succeeded) {
> > + // remove temp results for the next try
> > + principal = null;
> > + }
> > + if (krb5PrincName != null && krb5PrincName.length() != 0) {
> > + krb5PrincName.delete(0, krb5PrincName.length());
> > + }
> > + krb5PrincName = null;
> > + }
> > +}
> >
> >
> >
> >
> >
> > --
> >
> > Colm O hEigeartaigh
> >
> > Talend Community Coder
> > http://coders.talend.com
> >
>
>
>
> --
> Colm O hEigeartaigh
>
> Talend Community Coder
> http://coders.talend.com
>
--
Colm O hEigeartaigh
Talend Community Coder
http://coders.talend.com
RE: directory-kerby git commit: DIRKRB-681 Add new LoginModule
Posted by "Li, Jiajia" <ji...@intel.com>.
The error occurred after upgrading the mvn version to 3.5.2, I've fixed it. Thanks Colm.
Regards,
Jiajia
-----Original Message-----
From: Colm O hEigeartaigh [mailto:coheigea@apache.org]
Sent: Thursday, January 25, 2018 5:43 PM
To: Li, Jiajia <ji...@intel.com>
Cc: kerby@directory.apache.org
Subject: Re: directory-kerby git commit: DIRKRB-681 Add new LoginModule
Apache Maven 3.5.2 (138edd61fd100ec658bfa2d307c43b76940a5d7d;
2017-10-18T08:58:13+01:00)
Maven home: /opt/apache-maven-3.5.2
Java version: 1.8.0_151, vendor: Oracle Corporation Java home: /opt/jdk1.8.0_151/jre Default locale: en_GB, platform encoding: UTF-8 OS name: "linux", version: "4.13.0-25-generic", arch: "amd64", family:
"unix"
Is the modernizer plugin running when you do "mvn clean install"?
Colm.
On Thu, Jan 25, 2018 at 8:13 AM, Li, Jiajia <ji...@intel.com> wrote:
> Hi Colm,
>
>
>
> I can’t reproduce this build failure, could you provide the java and
> OS version?
>
>
>
> Thanks,
>
> Jiajia
>
>
>
> *From:* Colm O hEigeartaigh [mailto:coheigea@apache.org]
> *Sent:* Wednesday, January 24, 2018 11:30 PM
> *To:* kerby@directory.apache.org; Li, Jiajia <ji...@intel.com>
> *Subject:* Re: directory-kerby git commit: DIRKRB-681 Add new
> LoginModule
>
>
>
> Hi Jiajia,
>
> This commit is causing a build failure:
>
> [INFO] --- modernizer-maven-plugin:1.5.0:modernizer (modernizer-check)
> @ has-client --- [ERROR]
> /home/colm/src/apache/directory-kerby/has-project/
> has-client/src/main/java/org/apache/kerby/has/client/HasLoginModule.java:160:
> Prefer java.lang.StringBuilder
> [ERROR] /home/colm/src/apache/directory-kerby/has-project/
> has-client/src/main/java/org/apache/kerby/has/client/HasLoginModule.java:163:
> Prefer java.lang.StringBuilder
>
> Colm.
>
>
>
> On Mon, Jan 22, 2018 at 3:28 AM, <pl...@apache.org> wrote:
>
> Repository: directory-kerby
> Updated Branches:
> refs/heads/trunk a8a284d9c -> 34ccabec6
>
>
> DIRKRB-681 Add new LoginModule
>
>
> Project: http://git-wip-us.apache.org/repos/asf/directory-kerby/repo
> Commit: http://git-wip-us.apache.org/repos/asf/directory-kerby/
> commit/34ccabec
> Tree:
> http://git-wip-us.apache.org/repos/asf/directory-kerby/tree/34ccabec
> Diff:
> http://git-wip-us.apache.org/repos/asf/directory-kerby/diff/34ccabec
>
> Branch: refs/heads/trunk
> Commit: 34ccabec68b2b83b683240801e3929ef43eec26e
> Parents: a8a284d
> Author: plusplusjiajia <ji...@intel.com>
> Authored: Mon Jan 22 11:25:06 2018 +0800
> Committer: plusplusjiajia <ji...@intel.com>
> Committed: Mon Jan 22 11:25:06 2018 +0800
>
> ----------------------------------------------------------------------
> .../apache/kerby/has/client/HasLoginModule.java | 456
> +++++++++++++++++++
> 1 file changed, 456 insertions(+)
> ----------------------------------------------------------------------
>
>
> http://git-wip-us.apache.org/repos/asf/directory-kerby/
> blob/34ccabec/has-project/has-client/src/main/java/org/
> apache/kerby/has/client/HasLoginModule.java
> ----------------------------------------------------------------------
> diff --git
> a/has-project/has-client/src/main/java/org/apache/kerby/has/client/Has
> LoginModule.java
> b/has-project/has-client/src/main/java/org/apache/kerby/
> has/client/HasLoginModule.java
> new file mode 100644
> index 0000000..8debda5
> --- /dev/null
> +++ b/has-project/has-client/src/main/java/org/apache/kerby/
> has/client/HasLoginModule.java
> @@ -0,0 +1,456 @@
> +/**
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements. See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership. The ASF licenses this file
> + * to you under the Apache License, Version 2.0 (the
> + * "License"); you may not use this file except in compliance
> + * with the License. You may obtain a copy of the License at
> + * <p>
> + * http://www.apache.org/licenses/LICENSE-2.0
> + * <p>
> + * Unless required by applicable law or agreed to in writing,
> + * software distributed under the License is distributed on an
> + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
> + * KIND, either express or implied. See the License for the
> + * specific language governing permissions and limitations
> + * under the License.
> + */
> +package org.apache.kerby.has.client;
> +
> +import com.sun.security.auth.module.Krb5LoginModule;
> +import org.apache.kerby.has.common.HasException;
> +import org.apache.kerby.kerberos.kerb.ccache.Credential;
> +import org.apache.kerby.kerberos.kerb.type.ticket.TgtTicket;
> +import org.slf4j.Logger;
> +import org.slf4j.LoggerFactory;
> +import sun.security.jgss.krb5.Krb5Util; import
> +sun.security.krb5.Credentials; import sun.security.krb5.KrbException;
> +import sun.security.krb5.PrincipalName;
> +
> +import javax.security.auth.DestroyFailedException;
> +import javax.security.auth.Subject;
> +import javax.security.auth.callback.CallbackHandler;
> +import javax.security.auth.kerberos.KerberosPrincipal;
> +import javax.security.auth.kerberos.KerberosTicket;
> +import javax.security.auth.login.LoginException;
> +import javax.security.auth.spi.LoginModule;
> +import java.io.IOException;
> +import java.security.Principal;
> +import java.util.Date;
> +import java.util.Iterator;
> +import java.util.Map;
> +import java.util.Set;
> +
> +/**
> + * This <code>LoginModule</code> authenticates users using tgt ticket
> + * The client's TGT will be retrieved from the API of HasClient */
> +public class HasLoginModule implements LoginModule {
> +
> + public static final Logger LOG = LoggerFactory.getLogger(
> HasLoginModule.class);
> +
> + Krb5LoginModule krb5LoginModule;
> +
> + // initial state
> + private Subject subject;
> +
> + // configurable option
> + private boolean debug = false;
> + private boolean doNotPrompt = false;
> + private boolean useTgtTicket = false;
> + private String hadoopSecurityHas = null;
> + private String princName = null;
> +
> + private boolean refreshKrb5Config = false;
> +
> + // specify if initiator.
> + // perform authentication exchange if initiator
> + private boolean isInitiator = true;
> +
> + // the authentication status
> + private boolean succeeded = false;
> + private boolean commitSucceeded = false;
> +
> + private Credentials cred = null;
> +
> + private PrincipalName principal = null;
> + private KerberosPrincipal kerbClientPrinc = null;
> + private KerberosTicket kerbTicket = null;
> + private StringBuffer krb5PrincName = null;
> + private boolean unboundServer = false;
> +
> + /**
> + * Initialize this <code>LoginModule</code>.
> + *
> + * @param subject the <code>Subject</code> to be
> authenticated. <p>
> + * @param callbackHandler a <code>CallbackHandler</code> for
> + * communication with the end user (prompting
> for
> + * usernames and passwords, for example). <p>
> + * @param sharedState shared <code>LoginModule</code> state. <p>
> + * @param options options specified in the login
> + * <code>Configuration</code> for this
> particular
> + * <code>LoginModule</code>.
> + */
> + public void initialize(Subject subject,
> + CallbackHandler callbackHandler,
> + Map<String, ?> sharedState,
> + Map<String, ?> options) {
> +
> + this.subject = subject;
> +
> + // initialize any configured options
> + useTgtTicket = "true".equalsIgnoreCase((String)
> options.get("useTgtTicket"));
> +
> + if (useTgtTicket) {
> + debug = "true".equalsIgnoreCase((String)
> options.get("debug"));
> + doNotPrompt = "true".equalsIgnoreCase((String)
> options.get("doNotPrompt"));
> + useTgtTicket = "true".equalsIgnoreCase((String)
> options.get("useTgtTicket"));
> + hadoopSecurityHas = (String) options.get("
> hadoopSecurityHas");
> + princName = (String) options.get("principal");
> + refreshKrb5Config =
> + "true".equalsIgnoreCase((String) options.get("
> refreshKrb5Config"));
> +
> + // check isInitiator value
> + String isInitiatorValue = ((String)
> options.get("isInitiator"));
> + if (isInitiatorValue != null) {
> + // use default, if value not set
> + isInitiator = "true".equalsIgnoreCase(isInitiatorValue);
> + }
> +
> + if (debug) {
> + System.out.print("Debug is " + debug
> + + " doNotPrompt " + doNotPrompt
> + + " isInitiator " + isInitiator
> + + " refreshKrb5Config is " + refreshKrb5Config
> + + " principal is " + princName + "\n");
> + }
> + } else {
> + krb5LoginModule = new Krb5LoginModule();
> + krb5LoginModule.initialize(subject, callbackHandler,
> sharedState, options);
> + }
> + }
> +
> + /**
> + * Authenticate the user
> + *
> + * @return true in all cases since this <code>LoginModule</code>
> + * should not be ignored.
> + * @throws LoginException if this <code>LoginModule</code>
> + * is unable to perform the
> authentication.
> + */
> + public boolean login() throws LoginException {
> +
> + if (useTgtTicket) {
> + if (refreshKrb5Config) {
> + try {
> + if (debug) {
> + System.out.println("Refreshing Kerberos
> configuration");
> + }
> + sun.security.krb5.Config.refresh();
> + } catch (KrbException ke) {
> + LoginException le = new
> + LoginException(ke.getMessage()
> );
> + le.initCause(ke);
> + throw le;
> + }
> + }
> + String principalProperty = System.getProperty("sun.
> security.krb5.principal");
> + if (principalProperty != null) {
> + krb5PrincName = new StringBuffer(principalProperty);
> + } else {
> + if (princName != null) {
> + krb5PrincName = new StringBuffer(princName);
> + }
> + }
> +
> + validateConfiguration();
> +
> + if (krb5PrincName != null &&
> + krb5PrincName.toString().equals("*"))
> {
> + unboundServer = true;
> + }
> +
> + // attempt the authentication by getting the username and pwd
> + // by prompting or configuration i.e. not from shared
> + state
> +
> + try {
> + attemptAuthentication();
> + succeeded = true;
> + cleanState();
> + return true;
> + } catch (LoginException e) {
> + // authentication failed -- clean out state
> + if (debug) {
> + System.out.println("\t\t[HasLoginModule] "
> + + "authentication failed \n"
> + + e.getMessage());
> + }
> + succeeded = false;
> + cleanState();
> + throw e;
> + }
> + } else {
> + succeeded = krb5LoginModule.login();
> + return succeeded;
> + }
> + }
> +
> + /**
> + * Process the configuration options
> + * Get the TGT from Has Client
> + */
> + private void attemptAuthentication()
> + throws LoginException {
> +
> + /*
> + * Check the creds cache to see whether
> + * we have TGT for this client principal
> + */
> + if (krb5PrincName != null) {
> + try {
> + principal = new PrincipalName(krb5PrincName.toString(),
> + PrincipalName.KRB_NT_PRINCIPAL);
> + } catch (KrbException e) {
> + LoginException le = new LoginException(e.getMessage());
> + le.initCause(e);
> + throw le;
> + }
> + }
> +
> + try {
> + if (useTgtTicket) {
> + if (debug) {
> + System.out.println("use tgt ticket to login,
> + acquire
> TGT TICKET...");
> + }
> +
> + HasClient hasClient = new HasClient(hadoopSecurityHas);
> + TgtTicket tgtTicket = null;
> + try {
> + tgtTicket = hasClient.requestTgt();
> + } catch (HasException e) {
> + LoginException le = new
> + LoginException(e.getMessage())
> ;
> + le.initCause(e);
> + throw le;
> + }
> + Credential credential = new Credential(tgtTicket);
> + boolean[] flags = new boolean[7];
> + int flag = credential.getTicketFlags().getFlags();
> + for (int i = 6; i >= 0; i--) {
> + flags[i] = (flag & (1 << i)) != 0;
> + }
> + Date startTime = null;
> + if (credential.getStartTime() != null) {
> + startTime = credential.getStartTime().getValue();
> + }
> + cred = new Credentials(credential.getTicket().encode(),
> + credential.getClientName().getName(),
> + credential.getServerName().getName(),
> + credential.getKey().getKeyData(),
> + credential.getKey().getKeyType().getValue(),
> + flags,
> + credential.getAuthTime().getValue(),
> + startTime,
> + credential.getEndTime().getValue(),
> + credential.getRenewTill().getValue(),
> + null);
> +
> + // get the principal name from the ticket cache
> + if (cred != null && principal == null) {
> + principal = cred.getClient();
> + }
> + if (debug) {
> + System.out.println("Principal is " + principal);
> + if (cred == null) {
> + System.out.println("null credentials from TGT
> Ticket");
> + }
> + }
> + }
> + } catch (KrbException e) {
> + LoginException le = new LoginException(e.getMessage());
> + le.initCause(e);
> + throw le;
> + } catch (IOException ioe) {
> + LoginException ie = new LoginException(ioe.getMessage());
> + ie.initCause(ioe);
> + throw ie;
> + }
> + }
> +
> + private void validateConfiguration() throws LoginException {
> + if (doNotPrompt && !useTgtTicket) {
> + throw new LoginException("Configuration Error"
> + + " - either doNotPrompt should be "
> + + " false or"
> + + " useTgtTicket"
> + + " should be true");
> + }
> +
> + if (krb5PrincName != null &&
> + krb5PrincName.toString().equals("*")
> && isInitiator) {
> + throw new LoginException("Configuration Error"
> + + " - principal cannot be * when isInitiator is true");
> + }
> + }
> +
> + /**
> + * <p> This method is called if the LoginContext's
> + * overall authentication succeeded
> + *
> + * @return true if this LoginModule's own login and commit
> + * attempts succeeded, or false otherwise.
> + * @throws LoginException if the commit fails.
> + */
> +
> + public boolean commit() throws LoginException {
> + if (debug) {
> + System.out.println("Login success? " + succeeded);
> + }
> +
> + if (useTgtTicket) {
> + if (succeeded == false) {
> + return false;
> + } else {
> + if (isInitiator && cred == null) {
> + succeeded = false;
> + throw new LoginException("Null Client Credential");
> + }
> +
> + if (subject.isReadOnly()) {
> + cleanKerberosCred();
> + throw new LoginException("Subject is Readonly");
> + }
> +
> + Set<Object> privCredSet =
> + subject.getPrivateCredentials(
> );
> + Set<Principal> princSet = subject.getPrincipals();
> + kerbClientPrinc = new KerberosPrincipal(principal.
> getName());
> +
> + // create Kerberos Ticket
> + if (isInitiator) {
> + kerbTicket = Krb5Util.credsToTicket(cred);
> + }
> +
> + // Let us add the kerbClientPrinc,kerbTicket
> +
> + // We won't add "*" as a KerberosPrincipal
> + if (!unboundServer
> + && !princSet.contains(kerbClientPrinc)) {
> + princSet.add(kerbClientPrinc);
> + }
> +
> + // add the TGT
> + if (kerbTicket != null &&
> + privCredSet.contains(kerbTicket))
> {
> + privCredSet.add(kerbTicket);
> + }
> + }
> + commitSucceeded = true;
> + if (debug) {
> + System.out.println("Commit Succeeded \n");
> + }
> + return true;
> + } else {
> + return krb5LoginModule.commit();
> + }
> + }
> +
> + /**
> + * <p> This method is called if the LoginContext's
> + * overall authentication failed.
> + *
> + * @return false if this LoginModule's own login and/or commit
> attempts
> + * failed, and true otherwise.
> + * @throws LoginException if the abort fails.
> + */
> +
> + public boolean abort() throws LoginException {
> + if (useTgtTicket) {
> + if (succeeded == false) {
> + return false;
> + } else if (succeeded == true && commitSucceeded == false) {
> + // login succeeded but overall authentication failed
> + succeeded = false;
> + cleanKerberosCred();
> + } else {
> + // overall authentication succeeded and commit succeeded,
> + // but someone else's commit failed
> + logout();
> + }
> + return true;
> + } else {
> + return krb5LoginModule.abort();
> + }
> + }
> +
> + /**
> + * Logout the user.
> + *
> + * @return true in all cases since this <code>LoginModule</code>
> + * should not be ignored.
> + * @throws LoginException if the logout fails.
> + */
> + public boolean logout() throws LoginException {
> +
> + if (useTgtTicket) {
> + if (debug) {
> + System.out.println("\t\t[Krb5LoginModule]: "
> + + "Entering logout");
> + }
> +
> + if (subject.isReadOnly()) {
> + cleanKerberosCred();
> + throw new LoginException("Subject is Readonly");
> + }
> +
> + subject.getPrincipals().remove(kerbClientPrinc);
> + // Let us remove all Kerberos credentials stored in the
> Subject
> + Iterator<Object> it = subject.getPrivateCredentials(
> ).iterator();
> + while (it.hasNext()) {
> + Object o = it.next();
> + if (o instanceof KerberosTicket) {
> + it.remove();
> + }
> + }
> + // clean the kerberos ticket and keys
> + cleanKerberosCred();
> +
> + succeeded = false;
> + commitSucceeded = false;
> + if (debug) {
> + System.out.println("\t\t[HasLoginModule]: "
> + + "logged out Subject");
> + }
> + return true;
> + } else {
> + return krb5LoginModule.logout();
> + }
> + }
> +
> + /**
> + * Clean Kerberos credentials
> + */
> + private void cleanKerberosCred() throws LoginException {
> + // Clean the ticket and server key
> + try {
> + if (kerbTicket != null) {
> + kerbTicket.destroy();
> + }
> + } catch (DestroyFailedException e) {
> + throw new LoginException("Destroy Failed on Kerberos
> + Private
> Credentials");
> + }
> + kerbTicket = null;
> + kerbClientPrinc = null;
> + }
> +
> + /**
> + * Clean out the state
> + */
> + private void cleanState() {
> +
> + if (!succeeded) {
> + // remove temp results for the next try
> + principal = null;
> + }
> + if (krb5PrincName != null && krb5PrincName.length() != 0) {
> + krb5PrincName.delete(0, krb5PrincName.length());
> + }
> + krb5PrincName = null;
> + }
> +}
>
>
>
>
>
> --
>
> Colm O hEigeartaigh
>
> Talend Community Coder
> http://coders.talend.com
>
--
Colm O hEigeartaigh
Talend Community Coder
http://coders.talend.com
Re: directory-kerby git commit: DIRKRB-681 Add new LoginModule
Posted by Colm O hEigeartaigh <co...@apache.org>.
Apache Maven 3.5.2 (138edd61fd100ec658bfa2d307c43b76940a5d7d;
2017-10-18T08:58:13+01:00)
Maven home: /opt/apache-maven-3.5.2
Java version: 1.8.0_151, vendor: Oracle Corporation
Java home: /opt/jdk1.8.0_151/jre
Default locale: en_GB, platform encoding: UTF-8
OS name: "linux", version: "4.13.0-25-generic", arch: "amd64", family:
"unix"
Is the modernizer plugin running when you do "mvn clean install"?
Colm.
On Thu, Jan 25, 2018 at 8:13 AM, Li, Jiajia <ji...@intel.com> wrote:
> Hi Colm,
>
>
>
> I can’t reproduce this build failure, could you provide the java and OS
> version?
>
>
>
> Thanks,
>
> Jiajia
>
>
>
> *From:* Colm O hEigeartaigh [mailto:coheigea@apache.org]
> *Sent:* Wednesday, January 24, 2018 11:30 PM
> *To:* kerby@directory.apache.org; Li, Jiajia <ji...@intel.com>
> *Subject:* Re: directory-kerby git commit: DIRKRB-681 Add new LoginModule
>
>
>
> Hi Jiajia,
>
> This commit is causing a build failure:
>
> [INFO] --- modernizer-maven-plugin:1.5.0:modernizer (modernizer-check) @
> has-client ---
> [ERROR] /home/colm/src/apache/directory-kerby/has-project/
> has-client/src/main/java/org/apache/kerby/has/client/HasLoginModule.java:160:
> Prefer java.lang.StringBuilder
> [ERROR] /home/colm/src/apache/directory-kerby/has-project/
> has-client/src/main/java/org/apache/kerby/has/client/HasLoginModule.java:163:
> Prefer java.lang.StringBuilder
>
> Colm.
>
>
>
> On Mon, Jan 22, 2018 at 3:28 AM, <pl...@apache.org> wrote:
>
> Repository: directory-kerby
> Updated Branches:
> refs/heads/trunk a8a284d9c -> 34ccabec6
>
>
> DIRKRB-681 Add new LoginModule
>
>
> Project: http://git-wip-us.apache.org/repos/asf/directory-kerby/repo
> Commit: http://git-wip-us.apache.org/repos/asf/directory-kerby/
> commit/34ccabec
> Tree: http://git-wip-us.apache.org/repos/asf/directory-kerby/tree/34ccabec
> Diff: http://git-wip-us.apache.org/repos/asf/directory-kerby/diff/34ccabec
>
> Branch: refs/heads/trunk
> Commit: 34ccabec68b2b83b683240801e3929ef43eec26e
> Parents: a8a284d
> Author: plusplusjiajia <ji...@intel.com>
> Authored: Mon Jan 22 11:25:06 2018 +0800
> Committer: plusplusjiajia <ji...@intel.com>
> Committed: Mon Jan 22 11:25:06 2018 +0800
>
> ----------------------------------------------------------------------
> .../apache/kerby/has/client/HasLoginModule.java | 456 +++++++++++++++++++
> 1 file changed, 456 insertions(+)
> ----------------------------------------------------------------------
>
>
> http://git-wip-us.apache.org/repos/asf/directory-kerby/
> blob/34ccabec/has-project/has-client/src/main/java/org/
> apache/kerby/has/client/HasLoginModule.java
> ----------------------------------------------------------------------
> diff --git a/has-project/has-client/src/main/java/org/apache/kerby/has/client/HasLoginModule.java
> b/has-project/has-client/src/main/java/org/apache/kerby/
> has/client/HasLoginModule.java
> new file mode 100644
> index 0000000..8debda5
> --- /dev/null
> +++ b/has-project/has-client/src/main/java/org/apache/kerby/
> has/client/HasLoginModule.java
> @@ -0,0 +1,456 @@
> +/**
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements. See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership. The ASF licenses this file
> + * to you under the Apache License, Version 2.0 (the
> + * "License"); you may not use this file except in compliance
> + * with the License. You may obtain a copy of the License at
> + * <p>
> + * http://www.apache.org/licenses/LICENSE-2.0
> + * <p>
> + * Unless required by applicable law or agreed to in writing,
> + * software distributed under the License is distributed on an
> + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
> + * KIND, either express or implied. See the License for the
> + * specific language governing permissions and limitations
> + * under the License.
> + */
> +package org.apache.kerby.has.client;
> +
> +import com.sun.security.auth.module.Krb5LoginModule;
> +import org.apache.kerby.has.common.HasException;
> +import org.apache.kerby.kerberos.kerb.ccache.Credential;
> +import org.apache.kerby.kerberos.kerb.type.ticket.TgtTicket;
> +import org.slf4j.Logger;
> +import org.slf4j.LoggerFactory;
> +import sun.security.jgss.krb5.Krb5Util;
> +import sun.security.krb5.Credentials;
> +import sun.security.krb5.KrbException;
> +import sun.security.krb5.PrincipalName;
> +
> +import javax.security.auth.DestroyFailedException;
> +import javax.security.auth.Subject;
> +import javax.security.auth.callback.CallbackHandler;
> +import javax.security.auth.kerberos.KerberosPrincipal;
> +import javax.security.auth.kerberos.KerberosTicket;
> +import javax.security.auth.login.LoginException;
> +import javax.security.auth.spi.LoginModule;
> +import java.io.IOException;
> +import java.security.Principal;
> +import java.util.Date;
> +import java.util.Iterator;
> +import java.util.Map;
> +import java.util.Set;
> +
> +/**
> + * This <code>LoginModule</code> authenticates users using tgt ticket
> + * The client's TGT will be retrieved from the API of HasClient
> + */
> +public class HasLoginModule implements LoginModule {
> +
> + public static final Logger LOG = LoggerFactory.getLogger(
> HasLoginModule.class);
> +
> + Krb5LoginModule krb5LoginModule;
> +
> + // initial state
> + private Subject subject;
> +
> + // configurable option
> + private boolean debug = false;
> + private boolean doNotPrompt = false;
> + private boolean useTgtTicket = false;
> + private String hadoopSecurityHas = null;
> + private String princName = null;
> +
> + private boolean refreshKrb5Config = false;
> +
> + // specify if initiator.
> + // perform authentication exchange if initiator
> + private boolean isInitiator = true;
> +
> + // the authentication status
> + private boolean succeeded = false;
> + private boolean commitSucceeded = false;
> +
> + private Credentials cred = null;
> +
> + private PrincipalName principal = null;
> + private KerberosPrincipal kerbClientPrinc = null;
> + private KerberosTicket kerbTicket = null;
> + private StringBuffer krb5PrincName = null;
> + private boolean unboundServer = false;
> +
> + /**
> + * Initialize this <code>LoginModule</code>.
> + *
> + * @param subject the <code>Subject</code> to be
> authenticated. <p>
> + * @param callbackHandler a <code>CallbackHandler</code> for
> + * communication with the end user (prompting
> for
> + * usernames and passwords, for example). <p>
> + * @param sharedState shared <code>LoginModule</code> state. <p>
> + * @param options options specified in the login
> + * <code>Configuration</code> for this
> particular
> + * <code>LoginModule</code>.
> + */
> + public void initialize(Subject subject,
> + CallbackHandler callbackHandler,
> + Map<String, ?> sharedState,
> + Map<String, ?> options) {
> +
> + this.subject = subject;
> +
> + // initialize any configured options
> + useTgtTicket = "true".equalsIgnoreCase((String)
> options.get("useTgtTicket"));
> +
> + if (useTgtTicket) {
> + debug = "true".equalsIgnoreCase((String)
> options.get("debug"));
> + doNotPrompt = "true".equalsIgnoreCase((String)
> options.get("doNotPrompt"));
> + useTgtTicket = "true".equalsIgnoreCase((String)
> options.get("useTgtTicket"));
> + hadoopSecurityHas = (String) options.get("
> hadoopSecurityHas");
> + princName = (String) options.get("principal");
> + refreshKrb5Config =
> + "true".equalsIgnoreCase((String) options.get("
> refreshKrb5Config"));
> +
> + // check isInitiator value
> + String isInitiatorValue = ((String)
> options.get("isInitiator"));
> + if (isInitiatorValue != null) {
> + // use default, if value not set
> + isInitiator = "true".equalsIgnoreCase(isInitiatorValue);
> + }
> +
> + if (debug) {
> + System.out.print("Debug is " + debug
> + + " doNotPrompt " + doNotPrompt
> + + " isInitiator " + isInitiator
> + + " refreshKrb5Config is " + refreshKrb5Config
> + + " principal is " + princName + "\n");
> + }
> + } else {
> + krb5LoginModule = new Krb5LoginModule();
> + krb5LoginModule.initialize(subject, callbackHandler,
> sharedState, options);
> + }
> + }
> +
> + /**
> + * Authenticate the user
> + *
> + * @return true in all cases since this <code>LoginModule</code>
> + * should not be ignored.
> + * @throws LoginException if this <code>LoginModule</code>
> + * is unable to perform the
> authentication.
> + */
> + public boolean login() throws LoginException {
> +
> + if (useTgtTicket) {
> + if (refreshKrb5Config) {
> + try {
> + if (debug) {
> + System.out.println("Refreshing Kerberos
> configuration");
> + }
> + sun.security.krb5.Config.refresh();
> + } catch (KrbException ke) {
> + LoginException le = new LoginException(ke.getMessage()
> );
> + le.initCause(ke);
> + throw le;
> + }
> + }
> + String principalProperty = System.getProperty("sun.
> security.krb5.principal");
> + if (principalProperty != null) {
> + krb5PrincName = new StringBuffer(principalProperty);
> + } else {
> + if (princName != null) {
> + krb5PrincName = new StringBuffer(princName);
> + }
> + }
> +
> + validateConfiguration();
> +
> + if (krb5PrincName != null && krb5PrincName.toString().equals("*"))
> {
> + unboundServer = true;
> + }
> +
> + // attempt the authentication by getting the username and pwd
> + // by prompting or configuration i.e. not from shared state
> +
> + try {
> + attemptAuthentication();
> + succeeded = true;
> + cleanState();
> + return true;
> + } catch (LoginException e) {
> + // authentication failed -- clean out state
> + if (debug) {
> + System.out.println("\t\t[HasLoginModule] "
> + + "authentication failed \n"
> + + e.getMessage());
> + }
> + succeeded = false;
> + cleanState();
> + throw e;
> + }
> + } else {
> + succeeded = krb5LoginModule.login();
> + return succeeded;
> + }
> + }
> +
> + /**
> + * Process the configuration options
> + * Get the TGT from Has Client
> + */
> + private void attemptAuthentication()
> + throws LoginException {
> +
> + /*
> + * Check the creds cache to see whether
> + * we have TGT for this client principal
> + */
> + if (krb5PrincName != null) {
> + try {
> + principal = new PrincipalName(krb5PrincName.toString(),
> + PrincipalName.KRB_NT_PRINCIPAL);
> + } catch (KrbException e) {
> + LoginException le = new LoginException(e.getMessage());
> + le.initCause(e);
> + throw le;
> + }
> + }
> +
> + try {
> + if (useTgtTicket) {
> + if (debug) {
> + System.out.println("use tgt ticket to login, acquire
> TGT TICKET...");
> + }
> +
> + HasClient hasClient = new HasClient(hadoopSecurityHas);
> + TgtTicket tgtTicket = null;
> + try {
> + tgtTicket = hasClient.requestTgt();
> + } catch (HasException e) {
> + LoginException le = new LoginException(e.getMessage())
> ;
> + le.initCause(e);
> + throw le;
> + }
> + Credential credential = new Credential(tgtTicket);
> + boolean[] flags = new boolean[7];
> + int flag = credential.getTicketFlags().getFlags();
> + for (int i = 6; i >= 0; i--) {
> + flags[i] = (flag & (1 << i)) != 0;
> + }
> + Date startTime = null;
> + if (credential.getStartTime() != null) {
> + startTime = credential.getStartTime().getValue();
> + }
> + cred = new Credentials(credential.getTicket().encode(),
> + credential.getClientName().getName(),
> + credential.getServerName().getName(),
> + credential.getKey().getKeyData(),
> + credential.getKey().getKeyType().getValue(),
> + flags,
> + credential.getAuthTime().getValue(),
> + startTime,
> + credential.getEndTime().getValue(),
> + credential.getRenewTill().getValue(),
> + null);
> +
> + // get the principal name from the ticket cache
> + if (cred != null && principal == null) {
> + principal = cred.getClient();
> + }
> + if (debug) {
> + System.out.println("Principal is " + principal);
> + if (cred == null) {
> + System.out.println("null credentials from TGT
> Ticket");
> + }
> + }
> + }
> + } catch (KrbException e) {
> + LoginException le = new LoginException(e.getMessage());
> + le.initCause(e);
> + throw le;
> + } catch (IOException ioe) {
> + LoginException ie = new LoginException(ioe.getMessage());
> + ie.initCause(ioe);
> + throw ie;
> + }
> + }
> +
> + private void validateConfiguration() throws LoginException {
> + if (doNotPrompt && !useTgtTicket) {
> + throw new LoginException("Configuration Error"
> + + " - either doNotPrompt should be "
> + + " false or"
> + + " useTgtTicket"
> + + " should be true");
> + }
> +
> + if (krb5PrincName != null && krb5PrincName.toString().equals("*")
> && isInitiator) {
> + throw new LoginException("Configuration Error"
> + + " - principal cannot be * when isInitiator is true");
> + }
> + }
> +
> + /**
> + * <p> This method is called if the LoginContext's
> + * overall authentication succeeded
> + *
> + * @return true if this LoginModule's own login and commit
> + * attempts succeeded, or false otherwise.
> + * @throws LoginException if the commit fails.
> + */
> +
> + public boolean commit() throws LoginException {
> + if (debug) {
> + System.out.println("Login success? " + succeeded);
> + }
> +
> + if (useTgtTicket) {
> + if (succeeded == false) {
> + return false;
> + } else {
> + if (isInitiator && cred == null) {
> + succeeded = false;
> + throw new LoginException("Null Client Credential");
> + }
> +
> + if (subject.isReadOnly()) {
> + cleanKerberosCred();
> + throw new LoginException("Subject is Readonly");
> + }
> +
> + Set<Object> privCredSet = subject.getPrivateCredentials(
> );
> + Set<Principal> princSet = subject.getPrincipals();
> + kerbClientPrinc = new KerberosPrincipal(principal.
> getName());
> +
> + // create Kerberos Ticket
> + if (isInitiator) {
> + kerbTicket = Krb5Util.credsToTicket(cred);
> + }
> +
> + // Let us add the kerbClientPrinc,kerbTicket
> +
> + // We won't add "*" as a KerberosPrincipal
> + if (!unboundServer
> + && !princSet.contains(kerbClientPrinc)) {
> + princSet.add(kerbClientPrinc);
> + }
> +
> + // add the TGT
> + if (kerbTicket != null && privCredSet.contains(kerbTicket))
> {
> + privCredSet.add(kerbTicket);
> + }
> + }
> + commitSucceeded = true;
> + if (debug) {
> + System.out.println("Commit Succeeded \n");
> + }
> + return true;
> + } else {
> + return krb5LoginModule.commit();
> + }
> + }
> +
> + /**
> + * <p> This method is called if the LoginContext's
> + * overall authentication failed.
> + *
> + * @return false if this LoginModule's own login and/or commit
> attempts
> + * failed, and true otherwise.
> + * @throws LoginException if the abort fails.
> + */
> +
> + public boolean abort() throws LoginException {
> + if (useTgtTicket) {
> + if (succeeded == false) {
> + return false;
> + } else if (succeeded == true && commitSucceeded == false) {
> + // login succeeded but overall authentication failed
> + succeeded = false;
> + cleanKerberosCred();
> + } else {
> + // overall authentication succeeded and commit succeeded,
> + // but someone else's commit failed
> + logout();
> + }
> + return true;
> + } else {
> + return krb5LoginModule.abort();
> + }
> + }
> +
> + /**
> + * Logout the user.
> + *
> + * @return true in all cases since this <code>LoginModule</code>
> + * should not be ignored.
> + * @throws LoginException if the logout fails.
> + */
> + public boolean logout() throws LoginException {
> +
> + if (useTgtTicket) {
> + if (debug) {
> + System.out.println("\t\t[Krb5LoginModule]: "
> + + "Entering logout");
> + }
> +
> + if (subject.isReadOnly()) {
> + cleanKerberosCred();
> + throw new LoginException("Subject is Readonly");
> + }
> +
> + subject.getPrincipals().remove(kerbClientPrinc);
> + // Let us remove all Kerberos credentials stored in the
> Subject
> + Iterator<Object> it = subject.getPrivateCredentials(
> ).iterator();
> + while (it.hasNext()) {
> + Object o = it.next();
> + if (o instanceof KerberosTicket) {
> + it.remove();
> + }
> + }
> + // clean the kerberos ticket and keys
> + cleanKerberosCred();
> +
> + succeeded = false;
> + commitSucceeded = false;
> + if (debug) {
> + System.out.println("\t\t[HasLoginModule]: "
> + + "logged out Subject");
> + }
> + return true;
> + } else {
> + return krb5LoginModule.logout();
> + }
> + }
> +
> + /**
> + * Clean Kerberos credentials
> + */
> + private void cleanKerberosCred() throws LoginException {
> + // Clean the ticket and server key
> + try {
> + if (kerbTicket != null) {
> + kerbTicket.destroy();
> + }
> + } catch (DestroyFailedException e) {
> + throw new LoginException("Destroy Failed on Kerberos Private
> Credentials");
> + }
> + kerbTicket = null;
> + kerbClientPrinc = null;
> + }
> +
> + /**
> + * Clean out the state
> + */
> + private void cleanState() {
> +
> + if (!succeeded) {
> + // remove temp results for the next try
> + principal = null;
> + }
> + if (krb5PrincName != null && krb5PrincName.length() != 0) {
> + krb5PrincName.delete(0, krb5PrincName.length());
> + }
> + krb5PrincName = null;
> + }
> +}
>
>
>
>
>
> --
>
> Colm O hEigeartaigh
>
> Talend Community Coder
> http://coders.talend.com
>
--
Colm O hEigeartaigh
Talend Community Coder
http://coders.talend.com
RE: directory-kerby git commit: DIRKRB-681 Add new LoginModule
Posted by "Li, Jiajia" <ji...@intel.com>.
Hi Colm,
I can’t reproduce this build failure, could you provide the java and OS version?
Thanks,
Jiajia
From: Colm O hEigeartaigh [mailto:coheigea@apache.org]
Sent: Wednesday, January 24, 2018 11:30 PM
To: kerby@directory.apache.org; Li, Jiajia <ji...@intel.com>
Subject: Re: directory-kerby git commit: DIRKRB-681 Add new LoginModule
Hi Jiajia,
This commit is causing a build failure:
[INFO] --- modernizer-maven-plugin:1.5.0:modernizer (modernizer-check) @ has-client ---
[ERROR] /home/colm/src/apache/directory-kerby/has-project/has-client/src/main/java/org/apache/kerby/has/client/HasLoginModule.java:160: Prefer java.lang.StringBuilder
[ERROR] /home/colm/src/apache/directory-kerby/has-project/has-client/src/main/java/org/apache/kerby/has/client/HasLoginModule.java:163: Prefer java.lang.StringBuilder
Colm.
On Mon, Jan 22, 2018 at 3:28 AM, <pl...@apache.org>> wrote:
Repository: directory-kerby
Updated Branches:
refs/heads/trunk a8a284d9c -> 34ccabec6
DIRKRB-681 Add new LoginModule
Project: http://git-wip-us.apache.org/repos/asf/directory-kerby/repo
Commit: http://git-wip-us.apache.org/repos/asf/directory-kerby/commit/34ccabec
Tree: http://git-wip-us.apache.org/repos/asf/directory-kerby/tree/34ccabec
Diff: http://git-wip-us.apache.org/repos/asf/directory-kerby/diff/34ccabec
Branch: refs/heads/trunk
Commit: 34ccabec68b2b83b683240801e3929ef43eec26e
Parents: a8a284d
Author: plusplusjiajia <ji...@intel.com>>
Authored: Mon Jan 22 11:25:06 2018 +0800
Committer: plusplusjiajia <ji...@intel.com>>
Committed: Mon Jan 22 11:25:06 2018 +0800
----------------------------------------------------------------------
.../apache/kerby/has/client/HasLoginModule.java | 456 +++++++++++++++++++
1 file changed, 456 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/34ccabec/has-project/has-client/src/main/java/org/apache/kerby/has/client/HasLoginModule.java
----------------------------------------------------------------------
diff --git a/has-project/has-client/src/main/java/org/apache/kerby/has/client/HasLoginModule.java b/has-project/has-client/src/main/java/org/apache/kerby/has/client/HasLoginModule.java
new file mode 100644
index 0000000..8debda5
--- /dev/null
+++ b/has-project/has-client/src/main/java/org/apache/kerby/has/client/HasLoginModule.java
@@ -0,0 +1,456 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.kerby.has.client;
+
+import com.sun.security.auth.module.Krb5LoginModule;
+import org.apache.kerby.has.common.HasException;
+import org.apache.kerby.kerberos.kerb.ccache.Credential;
+import org.apache.kerby.kerberos.kerb.type.ticket.TgtTicket;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import sun.security.jgss.krb5.Krb5Util;
+import sun.security.krb5.Credentials;
+import sun.security.krb5.KrbException;
+import sun.security.krb5.PrincipalName;
+
+import javax.security.auth.DestroyFailedException;
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.kerberos.KerberosPrincipal;
+import javax.security.auth.kerberos.KerberosTicket;
+import javax.security.auth.login.LoginException;
+import javax.security.auth.spi.LoginModule;
+import java.io.IOException;
+import java.security.Principal;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * This <code>LoginModule</code> authenticates users using tgt ticket
+ * The client's TGT will be retrieved from the API of HasClient
+ */
+public class HasLoginModule implements LoginModule {
+
+ public static final Logger LOG = LoggerFactory.getLogger(HasLoginModule.class);
+
+ Krb5LoginModule krb5LoginModule;
+
+ // initial state
+ private Subject subject;
+
+ // configurable option
+ private boolean debug = false;
+ private boolean doNotPrompt = false;
+ private boolean useTgtTicket = false;
+ private String hadoopSecurityHas = null;
+ private String princName = null;
+
+ private boolean refreshKrb5Config = false;
+
+ // specify if initiator.
+ // perform authentication exchange if initiator
+ private boolean isInitiator = true;
+
+ // the authentication status
+ private boolean succeeded = false;
+ private boolean commitSucceeded = false;
+
+ private Credentials cred = null;
+
+ private PrincipalName principal = null;
+ private KerberosPrincipal kerbClientPrinc = null;
+ private KerberosTicket kerbTicket = null;
+ private StringBuffer krb5PrincName = null;
+ private boolean unboundServer = false;
+
+ /**
+ * Initialize this <code>LoginModule</code>.
+ *
+ * @param subject the <code>Subject</code> to be authenticated. <p>
+ * @param callbackHandler a <code>CallbackHandler</code> for
+ * communication with the end user (prompting for
+ * usernames and passwords, for example). <p>
+ * @param sharedState shared <code>LoginModule</code> state. <p>
+ * @param options options specified in the login
+ * <code>Configuration</code> for this particular
+ * <code>LoginModule</code>.
+ */
+ public void initialize(Subject subject,
+ CallbackHandler callbackHandler,
+ Map<String, ?> sharedState,
+ Map<String, ?> options) {
+
+ this.subject = subject;
+
+ // initialize any configured options
+ useTgtTicket = "true".equalsIgnoreCase((String) options.get("useTgtTicket"));
+
+ if (useTgtTicket) {
+ debug = "true".equalsIgnoreCase((String) options.get("debug"));
+ doNotPrompt = "true".equalsIgnoreCase((String) options.get("doNotPrompt"));
+ useTgtTicket = "true".equalsIgnoreCase((String) options.get("useTgtTicket"));
+ hadoopSecurityHas = (String) options.get("hadoopSecurityHas");
+ princName = (String) options.get("principal");
+ refreshKrb5Config =
+ "true".equalsIgnoreCase((String) options.get("refreshKrb5Config"));
+
+ // check isInitiator value
+ String isInitiatorValue = ((String) options.get("isInitiator"));
+ if (isInitiatorValue != null) {
+ // use default, if value not set
+ isInitiator = "true".equalsIgnoreCase(isInitiatorValue);
+ }
+
+ if (debug) {
+ System.out.print("Debug is " + debug
+ + " doNotPrompt " + doNotPrompt
+ + " isInitiator " + isInitiator
+ + " refreshKrb5Config is " + refreshKrb5Config
+ + " principal is " + princName + "\n");
+ }
+ } else {
+ krb5LoginModule = new Krb5LoginModule();
+ krb5LoginModule.initialize(subject, callbackHandler, sharedState, options);
+ }
+ }
+
+ /**
+ * Authenticate the user
+ *
+ * @return true in all cases since this <code>LoginModule</code>
+ * should not be ignored.
+ * @throws LoginException if this <code>LoginModule</code>
+ * is unable to perform the authentication.
+ */
+ public boolean login() throws LoginException {
+
+ if (useTgtTicket) {
+ if (refreshKrb5Config) {
+ try {
+ if (debug) {
+ System.out.println("Refreshing Kerberos configuration");
+ }
+ sun.security.krb5.Config.refresh();
+ } catch (KrbException ke) {
+ LoginException le = new LoginException(ke.getMessage());
+ le.initCause(ke);
+ throw le;
+ }
+ }
+ String principalProperty = System.getProperty("sun.security.krb5.principal");
+ if (principalProperty != null) {
+ krb5PrincName = new StringBuffer(principalProperty);
+ } else {
+ if (princName != null) {
+ krb5PrincName = new StringBuffer(princName);
+ }
+ }
+
+ validateConfiguration();
+
+ if (krb5PrincName != null && krb5PrincName.toString().equals("*")) {
+ unboundServer = true;
+ }
+
+ // attempt the authentication by getting the username and pwd
+ // by prompting or configuration i.e. not from shared state
+
+ try {
+ attemptAuthentication();
+ succeeded = true;
+ cleanState();
+ return true;
+ } catch (LoginException e) {
+ // authentication failed -- clean out state
+ if (debug) {
+ System.out.println("\t\t[HasLoginModule] "
+ + "authentication failed \n"
+ + e.getMessage());
+ }
+ succeeded = false;
+ cleanState();
+ throw e;
+ }
+ } else {
+ succeeded = krb5LoginModule.login();
+ return succeeded;
+ }
+ }
+
+ /**
+ * Process the configuration options
+ * Get the TGT from Has Client
+ */
+ private void attemptAuthentication()
+ throws LoginException {
+
+ /*
+ * Check the creds cache to see whether
+ * we have TGT for this client principal
+ */
+ if (krb5PrincName != null) {
+ try {
+ principal = new PrincipalName(krb5PrincName.toString(),
+ PrincipalName.KRB_NT_PRINCIPAL);
+ } catch (KrbException e) {
+ LoginException le = new LoginException(e.getMessage());
+ le.initCause(e);
+ throw le;
+ }
+ }
+
+ try {
+ if (useTgtTicket) {
+ if (debug) {
+ System.out.println("use tgt ticket to login, acquire TGT TICKET...");
+ }
+
+ HasClient hasClient = new HasClient(hadoopSecurityHas);
+ TgtTicket tgtTicket = null;
+ try {
+ tgtTicket = hasClient.requestTgt();
+ } catch (HasException e) {
+ LoginException le = new LoginException(e.getMessage());
+ le.initCause(e);
+ throw le;
+ }
+ Credential credential = new Credential(tgtTicket);
+ boolean[] flags = new boolean[7];
+ int flag = credential.getTicketFlags().getFlags();
+ for (int i = 6; i >= 0; i--) {
+ flags[i] = (flag & (1 << i)) != 0;
+ }
+ Date startTime = null;
+ if (credential.getStartTime() != null) {
+ startTime = credential.getStartTime().getValue();
+ }
+ cred = new Credentials(credential.getTicket().encode(),
+ credential.getClientName().getName(),
+ credential.getServerName().getName(),
+ credential.getKey().getKeyData(),
+ credential.getKey().getKeyType().getValue(),
+ flags,
+ credential.getAuthTime().getValue(),
+ startTime,
+ credential.getEndTime().getValue(),
+ credential.getRenewTill().getValue(),
+ null);
+
+ // get the principal name from the ticket cache
+ if (cred != null && principal == null) {
+ principal = cred.getClient();
+ }
+ if (debug) {
+ System.out.println("Principal is " + principal);
+ if (cred == null) {
+ System.out.println("null credentials from TGT Ticket");
+ }
+ }
+ }
+ } catch (KrbException e) {
+ LoginException le = new LoginException(e.getMessage());
+ le.initCause(e);
+ throw le;
+ } catch (IOException ioe) {
+ LoginException ie = new LoginException(ioe.getMessage());
+ ie.initCause(ioe);
+ throw ie;
+ }
+ }
+
+ private void validateConfiguration() throws LoginException {
+ if (doNotPrompt && !useTgtTicket) {
+ throw new LoginException("Configuration Error"
+ + " - either doNotPrompt should be "
+ + " false or"
+ + " useTgtTicket"
+ + " should be true");
+ }
+
+ if (krb5PrincName != null && krb5PrincName.toString().equals("*") && isInitiator) {
+ throw new LoginException("Configuration Error"
+ + " - principal cannot be * when isInitiator is true");
+ }
+ }
+
+ /**
+ * <p> This method is called if the LoginContext's
+ * overall authentication succeeded
+ *
+ * @return true if this LoginModule's own login and commit
+ * attempts succeeded, or false otherwise.
+ * @throws LoginException if the commit fails.
+ */
+
+ public boolean commit() throws LoginException {
+ if (debug) {
+ System.out.println("Login success? " + succeeded);
+ }
+
+ if (useTgtTicket) {
+ if (succeeded == false) {
+ return false;
+ } else {
+ if (isInitiator && cred == null) {
+ succeeded = false;
+ throw new LoginException("Null Client Credential");
+ }
+
+ if (subject.isReadOnly()) {
+ cleanKerberosCred();
+ throw new LoginException("Subject is Readonly");
+ }
+
+ Set<Object> privCredSet = subject.getPrivateCredentials();
+ Set<Principal> princSet = subject.getPrincipals();
+ kerbClientPrinc = new KerberosPrincipal(principal.getName());
+
+ // create Kerberos Ticket
+ if (isInitiator) {
+ kerbTicket = Krb5Util.credsToTicket(cred);
+ }
+
+ // Let us add the kerbClientPrinc,kerbTicket
+
+ // We won't add "*" as a KerberosPrincipal
+ if (!unboundServer
+ && !princSet.contains(kerbClientPrinc)) {
+ princSet.add(kerbClientPrinc);
+ }
+
+ // add the TGT
+ if (kerbTicket != null && privCredSet.contains(kerbTicket)) {
+ privCredSet.add(kerbTicket);
+ }
+ }
+ commitSucceeded = true;
+ if (debug) {
+ System.out.println("Commit Succeeded \n");
+ }
+ return true;
+ } else {
+ return krb5LoginModule.commit();
+ }
+ }
+
+ /**
+ * <p> This method is called if the LoginContext's
+ * overall authentication failed.
+ *
+ * @return false if this LoginModule's own login and/or commit attempts
+ * failed, and true otherwise.
+ * @throws LoginException if the abort fails.
+ */
+
+ public boolean abort() throws LoginException {
+ if (useTgtTicket) {
+ if (succeeded == false) {
+ return false;
+ } else if (succeeded == true && commitSucceeded == false) {
+ // login succeeded but overall authentication failed
+ succeeded = false;
+ cleanKerberosCred();
+ } else {
+ // overall authentication succeeded and commit succeeded,
+ // but someone else's commit failed
+ logout();
+ }
+ return true;
+ } else {
+ return krb5LoginModule.abort();
+ }
+ }
+
+ /**
+ * Logout the user.
+ *
+ * @return true in all cases since this <code>LoginModule</code>
+ * should not be ignored.
+ * @throws LoginException if the logout fails.
+ */
+ public boolean logout() throws LoginException {
+
+ if (useTgtTicket) {
+ if (debug) {
+ System.out.println("\t\t[Krb5LoginModule]: "
+ + "Entering logout");
+ }
+
+ if (subject.isReadOnly()) {
+ cleanKerberosCred();
+ throw new LoginException("Subject is Readonly");
+ }
+
+ subject.getPrincipals().remove(kerbClientPrinc);
+ // Let us remove all Kerberos credentials stored in the Subject
+ Iterator<Object> it = subject.getPrivateCredentials().iterator();
+ while (it.hasNext()) {
+ Object o = it.next();
+ if (o instanceof KerberosTicket) {
+ it.remove();
+ }
+ }
+ // clean the kerberos ticket and keys
+ cleanKerberosCred();
+
+ succeeded = false;
+ commitSucceeded = false;
+ if (debug) {
+ System.out.println("\t\t[HasLoginModule]: "
+ + "logged out Subject");
+ }
+ return true;
+ } else {
+ return krb5LoginModule.logout();
+ }
+ }
+
+ /**
+ * Clean Kerberos credentials
+ */
+ private void cleanKerberosCred() throws LoginException {
+ // Clean the ticket and server key
+ try {
+ if (kerbTicket != null) {
+ kerbTicket.destroy();
+ }
+ } catch (DestroyFailedException e) {
+ throw new LoginException("Destroy Failed on Kerberos Private Credentials");
+ }
+ kerbTicket = null;
+ kerbClientPrinc = null;
+ }
+
+ /**
+ * Clean out the state
+ */
+ private void cleanState() {
+
+ if (!succeeded) {
+ // remove temp results for the next try
+ principal = null;
+ }
+ if (krb5PrincName != null && krb5PrincName.length() != 0) {
+ krb5PrincName.delete(0, krb5PrincName.length());
+ }
+ krb5PrincName = null;
+ }
+}
--
Colm O hEigeartaigh
Talend Community Coder
http://coders.talend.com
Re: directory-kerby git commit: DIRKRB-681 Add new LoginModule
Posted by Colm O hEigeartaigh <co...@apache.org>.
Hi Jiajia,
This commit is causing a build failure:
[INFO] --- modernizer-maven-plugin:1.5.0:modernizer (modernizer-check) @
has-client ---
[ERROR]
/home/colm/src/apache/directory-kerby/has-project/has-client/src/main/java/org/apache/kerby/has/client/HasLoginModule.java:160:
Prefer java.lang.StringBuilder
[ERROR]
/home/colm/src/apache/directory-kerby/has-project/has-client/src/main/java/org/apache/kerby/has/client/HasLoginModule.java:163:
Prefer java.lang.StringBuilder
Colm.
On Mon, Jan 22, 2018 at 3:28 AM, <pl...@apache.org> wrote:
> Repository: directory-kerby
> Updated Branches:
> refs/heads/trunk a8a284d9c -> 34ccabec6
>
>
> DIRKRB-681 Add new LoginModule
>
>
> Project: http://git-wip-us.apache.org/repos/asf/directory-kerby/repo
> Commit: http://git-wip-us.apache.org/repos/asf/directory-kerby/
> commit/34ccabec
> Tree: http://git-wip-us.apache.org/repos/asf/directory-kerby/tree/34ccabec
> Diff: http://git-wip-us.apache.org/repos/asf/directory-kerby/diff/34ccabec
>
> Branch: refs/heads/trunk
> Commit: 34ccabec68b2b83b683240801e3929ef43eec26e
> Parents: a8a284d
> Author: plusplusjiajia <ji...@intel.com>
> Authored: Mon Jan 22 11:25:06 2018 +0800
> Committer: plusplusjiajia <ji...@intel.com>
> Committed: Mon Jan 22 11:25:06 2018 +0800
>
> ----------------------------------------------------------------------
> .../apache/kerby/has/client/HasLoginModule.java | 456 +++++++++++++++++++
> 1 file changed, 456 insertions(+)
> ----------------------------------------------------------------------
>
>
> http://git-wip-us.apache.org/repos/asf/directory-kerby/
> blob/34ccabec/has-project/has-client/src/main/java/org/
> apache/kerby/has/client/HasLoginModule.java
> ----------------------------------------------------------------------
> diff --git a/has-project/has-client/src/main/java/org/apache/kerby/has/client/HasLoginModule.java
> b/has-project/has-client/src/main/java/org/apache/kerby/
> has/client/HasLoginModule.java
> new file mode 100644
> index 0000000..8debda5
> --- /dev/null
> +++ b/has-project/has-client/src/main/java/org/apache/kerby/
> has/client/HasLoginModule.java
> @@ -0,0 +1,456 @@
> +/**
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements. See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership. The ASF licenses this file
> + * to you under the Apache License, Version 2.0 (the
> + * "License"); you may not use this file except in compliance
> + * with the License. You may obtain a copy of the License at
> + * <p>
> + * http://www.apache.org/licenses/LICENSE-2.0
> + * <p>
> + * Unless required by applicable law or agreed to in writing,
> + * software distributed under the License is distributed on an
> + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
> + * KIND, either express or implied. See the License for the
> + * specific language governing permissions and limitations
> + * under the License.
> + */
> +package org.apache.kerby.has.client;
> +
> +import com.sun.security.auth.module.Krb5LoginModule;
> +import org.apache.kerby.has.common.HasException;
> +import org.apache.kerby.kerberos.kerb.ccache.Credential;
> +import org.apache.kerby.kerberos.kerb.type.ticket.TgtTicket;
> +import org.slf4j.Logger;
> +import org.slf4j.LoggerFactory;
> +import sun.security.jgss.krb5.Krb5Util;
> +import sun.security.krb5.Credentials;
> +import sun.security.krb5.KrbException;
> +import sun.security.krb5.PrincipalName;
> +
> +import javax.security.auth.DestroyFailedException;
> +import javax.security.auth.Subject;
> +import javax.security.auth.callback.CallbackHandler;
> +import javax.security.auth.kerberos.KerberosPrincipal;
> +import javax.security.auth.kerberos.KerberosTicket;
> +import javax.security.auth.login.LoginException;
> +import javax.security.auth.spi.LoginModule;
> +import java.io.IOException;
> +import java.security.Principal;
> +import java.util.Date;
> +import java.util.Iterator;
> +import java.util.Map;
> +import java.util.Set;
> +
> +/**
> + * This <code>LoginModule</code> authenticates users using tgt ticket
> + * The client's TGT will be retrieved from the API of HasClient
> + */
> +public class HasLoginModule implements LoginModule {
> +
> + public static final Logger LOG = LoggerFactory.getLogger(
> HasLoginModule.class);
> +
> + Krb5LoginModule krb5LoginModule;
> +
> + // initial state
> + private Subject subject;
> +
> + // configurable option
> + private boolean debug = false;
> + private boolean doNotPrompt = false;
> + private boolean useTgtTicket = false;
> + private String hadoopSecurityHas = null;
> + private String princName = null;
> +
> + private boolean refreshKrb5Config = false;
> +
> + // specify if initiator.
> + // perform authentication exchange if initiator
> + private boolean isInitiator = true;
> +
> + // the authentication status
> + private boolean succeeded = false;
> + private boolean commitSucceeded = false;
> +
> + private Credentials cred = null;
> +
> + private PrincipalName principal = null;
> + private KerberosPrincipal kerbClientPrinc = null;
> + private KerberosTicket kerbTicket = null;
> + private StringBuffer krb5PrincName = null;
> + private boolean unboundServer = false;
> +
> + /**
> + * Initialize this <code>LoginModule</code>.
> + *
> + * @param subject the <code>Subject</code> to be
> authenticated. <p>
> + * @param callbackHandler a <code>CallbackHandler</code> for
> + * communication with the end user (prompting
> for
> + * usernames and passwords, for example). <p>
> + * @param sharedState shared <code>LoginModule</code> state. <p>
> + * @param options options specified in the login
> + * <code>Configuration</code> for this
> particular
> + * <code>LoginModule</code>.
> + */
> + public void initialize(Subject subject,
> + CallbackHandler callbackHandler,
> + Map<String, ?> sharedState,
> + Map<String, ?> options) {
> +
> + this.subject = subject;
> +
> + // initialize any configured options
> + useTgtTicket = "true".equalsIgnoreCase((String)
> options.get("useTgtTicket"));
> +
> + if (useTgtTicket) {
> + debug = "true".equalsIgnoreCase((String)
> options.get("debug"));
> + doNotPrompt = "true".equalsIgnoreCase((String)
> options.get("doNotPrompt"));
> + useTgtTicket = "true".equalsIgnoreCase((String)
> options.get("useTgtTicket"));
> + hadoopSecurityHas = (String) options.get("
> hadoopSecurityHas");
> + princName = (String) options.get("principal");
> + refreshKrb5Config =
> + "true".equalsIgnoreCase((String) options.get("
> refreshKrb5Config"));
> +
> + // check isInitiator value
> + String isInitiatorValue = ((String)
> options.get("isInitiator"));
> + if (isInitiatorValue != null) {
> + // use default, if value not set
> + isInitiator = "true".equalsIgnoreCase(isInitiatorValue);
> + }
> +
> + if (debug) {
> + System.out.print("Debug is " + debug
> + + " doNotPrompt " + doNotPrompt
> + + " isInitiator " + isInitiator
> + + " refreshKrb5Config is " + refreshKrb5Config
> + + " principal is " + princName + "\n");
> + }
> + } else {
> + krb5LoginModule = new Krb5LoginModule();
> + krb5LoginModule.initialize(subject, callbackHandler,
> sharedState, options);
> + }
> + }
> +
> + /**
> + * Authenticate the user
> + *
> + * @return true in all cases since this <code>LoginModule</code>
> + * should not be ignored.
> + * @throws LoginException if this <code>LoginModule</code>
> + * is unable to perform the
> authentication.
> + */
> + public boolean login() throws LoginException {
> +
> + if (useTgtTicket) {
> + if (refreshKrb5Config) {
> + try {
> + if (debug) {
> + System.out.println("Refreshing Kerberos
> configuration");
> + }
> + sun.security.krb5.Config.refresh();
> + } catch (KrbException ke) {
> + LoginException le = new LoginException(ke.getMessage()
> );
> + le.initCause(ke);
> + throw le;
> + }
> + }
> + String principalProperty = System.getProperty("sun.
> security.krb5.principal");
> + if (principalProperty != null) {
> + krb5PrincName = new StringBuffer(principalProperty);
> + } else {
> + if (princName != null) {
> + krb5PrincName = new StringBuffer(princName);
> + }
> + }
> +
> + validateConfiguration();
> +
> + if (krb5PrincName != null && krb5PrincName.toString().equals("*"))
> {
> + unboundServer = true;
> + }
> +
> + // attempt the authentication by getting the username and pwd
> + // by prompting or configuration i.e. not from shared state
> +
> + try {
> + attemptAuthentication();
> + succeeded = true;
> + cleanState();
> + return true;
> + } catch (LoginException e) {
> + // authentication failed -- clean out state
> + if (debug) {
> + System.out.println("\t\t[HasLoginModule] "
> + + "authentication failed \n"
> + + e.getMessage());
> + }
> + succeeded = false;
> + cleanState();
> + throw e;
> + }
> + } else {
> + succeeded = krb5LoginModule.login();
> + return succeeded;
> + }
> + }
> +
> + /**
> + * Process the configuration options
> + * Get the TGT from Has Client
> + */
> + private void attemptAuthentication()
> + throws LoginException {
> +
> + /*
> + * Check the creds cache to see whether
> + * we have TGT for this client principal
> + */
> + if (krb5PrincName != null) {
> + try {
> + principal = new PrincipalName(krb5PrincName.toString(),
> + PrincipalName.KRB_NT_PRINCIPAL);
> + } catch (KrbException e) {
> + LoginException le = new LoginException(e.getMessage());
> + le.initCause(e);
> + throw le;
> + }
> + }
> +
> + try {
> + if (useTgtTicket) {
> + if (debug) {
> + System.out.println("use tgt ticket to login, acquire
> TGT TICKET...");
> + }
> +
> + HasClient hasClient = new HasClient(hadoopSecurityHas);
> + TgtTicket tgtTicket = null;
> + try {
> + tgtTicket = hasClient.requestTgt();
> + } catch (HasException e) {
> + LoginException le = new LoginException(e.getMessage())
> ;
> + le.initCause(e);
> + throw le;
> + }
> + Credential credential = new Credential(tgtTicket);
> + boolean[] flags = new boolean[7];
> + int flag = credential.getTicketFlags().getFlags();
> + for (int i = 6; i >= 0; i--) {
> + flags[i] = (flag & (1 << i)) != 0;
> + }
> + Date startTime = null;
> + if (credential.getStartTime() != null) {
> + startTime = credential.getStartTime().getValue();
> + }
> + cred = new Credentials(credential.getTicket().encode(),
> + credential.getClientName().getName(),
> + credential.getServerName().getName(),
> + credential.getKey().getKeyData(),
> + credential.getKey().getKeyType().getValue(),
> + flags,
> + credential.getAuthTime().getValue(),
> + startTime,
> + credential.getEndTime().getValue(),
> + credential.getRenewTill().getValue(),
> + null);
> +
> + // get the principal name from the ticket cache
> + if (cred != null && principal == null) {
> + principal = cred.getClient();
> + }
> + if (debug) {
> + System.out.println("Principal is " + principal);
> + if (cred == null) {
> + System.out.println("null credentials from TGT
> Ticket");
> + }
> + }
> + }
> + } catch (KrbException e) {
> + LoginException le = new LoginException(e.getMessage());
> + le.initCause(e);
> + throw le;
> + } catch (IOException ioe) {
> + LoginException ie = new LoginException(ioe.getMessage());
> + ie.initCause(ioe);
> + throw ie;
> + }
> + }
> +
> + private void validateConfiguration() throws LoginException {
> + if (doNotPrompt && !useTgtTicket) {
> + throw new LoginException("Configuration Error"
> + + " - either doNotPrompt should be "
> + + " false or"
> + + " useTgtTicket"
> + + " should be true");
> + }
> +
> + if (krb5PrincName != null && krb5PrincName.toString().equals("*")
> && isInitiator) {
> + throw new LoginException("Configuration Error"
> + + " - principal cannot be * when isInitiator is true");
> + }
> + }
> +
> + /**
> + * <p> This method is called if the LoginContext's
> + * overall authentication succeeded
> + *
> + * @return true if this LoginModule's own login and commit
> + * attempts succeeded, or false otherwise.
> + * @throws LoginException if the commit fails.
> + */
> +
> + public boolean commit() throws LoginException {
> + if (debug) {
> + System.out.println("Login success? " + succeeded);
> + }
> +
> + if (useTgtTicket) {
> + if (succeeded == false) {
> + return false;
> + } else {
> + if (isInitiator && cred == null) {
> + succeeded = false;
> + throw new LoginException("Null Client Credential");
> + }
> +
> + if (subject.isReadOnly()) {
> + cleanKerberosCred();
> + throw new LoginException("Subject is Readonly");
> + }
> +
> + Set<Object> privCredSet = subject.getPrivateCredentials(
> );
> + Set<Principal> princSet = subject.getPrincipals();
> + kerbClientPrinc = new KerberosPrincipal(principal.
> getName());
> +
> + // create Kerberos Ticket
> + if (isInitiator) {
> + kerbTicket = Krb5Util.credsToTicket(cred);
> + }
> +
> + // Let us add the kerbClientPrinc,kerbTicket
> +
> + // We won't add "*" as a KerberosPrincipal
> + if (!unboundServer
> + && !princSet.contains(kerbClientPrinc)) {
> + princSet.add(kerbClientPrinc);
> + }
> +
> + // add the TGT
> + if (kerbTicket != null && privCredSet.contains(kerbTicket))
> {
> + privCredSet.add(kerbTicket);
> + }
> + }
> + commitSucceeded = true;
> + if (debug) {
> + System.out.println("Commit Succeeded \n");
> + }
> + return true;
> + } else {
> + return krb5LoginModule.commit();
> + }
> + }
> +
> + /**
> + * <p> This method is called if the LoginContext's
> + * overall authentication failed.
> + *
> + * @return false if this LoginModule's own login and/or commit
> attempts
> + * failed, and true otherwise.
> + * @throws LoginException if the abort fails.
> + */
> +
> + public boolean abort() throws LoginException {
> + if (useTgtTicket) {
> + if (succeeded == false) {
> + return false;
> + } else if (succeeded == true && commitSucceeded == false) {
> + // login succeeded but overall authentication failed
> + succeeded = false;
> + cleanKerberosCred();
> + } else {
> + // overall authentication succeeded and commit succeeded,
> + // but someone else's commit failed
> + logout();
> + }
> + return true;
> + } else {
> + return krb5LoginModule.abort();
> + }
> + }
> +
> + /**
> + * Logout the user.
> + *
> + * @return true in all cases since this <code>LoginModule</code>
> + * should not be ignored.
> + * @throws LoginException if the logout fails.
> + */
> + public boolean logout() throws LoginException {
> +
> + if (useTgtTicket) {
> + if (debug) {
> + System.out.println("\t\t[Krb5LoginModule]: "
> + + "Entering logout");
> + }
> +
> + if (subject.isReadOnly()) {
> + cleanKerberosCred();
> + throw new LoginException("Subject is Readonly");
> + }
> +
> + subject.getPrincipals().remove(kerbClientPrinc);
> + // Let us remove all Kerberos credentials stored in the
> Subject
> + Iterator<Object> it = subject.getPrivateCredentials(
> ).iterator();
> + while (it.hasNext()) {
> + Object o = it.next();
> + if (o instanceof KerberosTicket) {
> + it.remove();
> + }
> + }
> + // clean the kerberos ticket and keys
> + cleanKerberosCred();
> +
> + succeeded = false;
> + commitSucceeded = false;
> + if (debug) {
> + System.out.println("\t\t[HasLoginModule]: "
> + + "logged out Subject");
> + }
> + return true;
> + } else {
> + return krb5LoginModule.logout();
> + }
> + }
> +
> + /**
> + * Clean Kerberos credentials
> + */
> + private void cleanKerberosCred() throws LoginException {
> + // Clean the ticket and server key
> + try {
> + if (kerbTicket != null) {
> + kerbTicket.destroy();
> + }
> + } catch (DestroyFailedException e) {
> + throw new LoginException("Destroy Failed on Kerberos Private
> Credentials");
> + }
> + kerbTicket = null;
> + kerbClientPrinc = null;
> + }
> +
> + /**
> + * Clean out the state
> + */
> + private void cleanState() {
> +
> + if (!succeeded) {
> + // remove temp results for the next try
> + principal = null;
> + }
> + if (krb5PrincName != null && krb5PrincName.length() != 0) {
> + krb5PrincName.delete(0, krb5PrincName.length());
> + }
> + krb5PrincName = null;
> + }
> +}
>
>
--
Colm O hEigeartaigh
Talend Community Coder
http://coders.talend.com