Path: blob/master/src/java.security.sasl/share/classes/com/sun/security/sasl/PlainClient.java
41161 views
/*1* Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package com.sun.security.sasl;2627import javax.security.sasl.*;2829import static java.nio.charset.StandardCharsets.UTF_8;3031/**32* Implements the PLAIN SASL client mechanism.33* (<A34* HREF="http://ftp.isi.edu/in-notes/rfc2595.txt">RFC 2595</A>)35*36* @author Rosanna Lee37*/38final class PlainClient implements SaslClient {39private boolean completed = false;40private byte[] pw;41private String authorizationID;42private String authenticationID;43private static byte SEP = 0; // US-ASCII <NUL>4445/**46* Creates a SASL mechanism with client credentials that it needs47* to participate in Plain authentication exchange with the server.48*49* @param authorizationID A possibly null string representing the principal50* for which authorization is being granted; if null, same as51* authenticationID52* @param authenticationID A non-null string representing the principal53* being authenticated. pw is associated with this principal.54* @param pw A non-null byte[] containing the password.55*/56PlainClient(String authorizationID, String authenticationID, byte[] pw)57throws SaslException {58if (authenticationID == null || pw == null) {59throw new SaslException(60"PLAIN: authorization ID and password must be specified");61}6263this.authorizationID = authorizationID;64this.authenticationID = authenticationID;65this.pw = pw; // caller should have already cloned66}6768/**69* Retrieves this mechanism's name for to initiate the PLAIN protocol70* exchange.71*72* @return The string "PLAIN".73*/74public String getMechanismName() {75return "PLAIN";76}7778public boolean hasInitialResponse() {79return true;80}8182public void dispose() throws SaslException {83clearPassword();84}8586/**87* Retrieves the initial response for the SASL command, which for88* PLAIN is the concatenation of authorization ID, authentication ID89* and password, with each component separated by the US-ASCII <NUL> byte.90*91* @param challengeData Ignored92* @return A non-null byte array containing the response to be sent to the server.93* @throws IllegalStateException if authentication already completed94*/95public byte[] evaluateChallenge(byte[] challengeData) {96if (completed) {97throw new IllegalStateException(98"PLAIN authentication already completed");99}100completed = true;101byte[] authz = (authorizationID != null)102? authorizationID.getBytes(UTF_8)103: null;104byte[] auth = authenticationID.getBytes(UTF_8);105106byte[] answer = new byte[pw.length + auth.length + 2 +107(authz == null ? 0 : authz.length)];108109int pos = 0;110if (authz != null) {111System.arraycopy(authz, 0, answer, 0, authz.length);112pos = authz.length;113}114answer[pos++] = SEP;115System.arraycopy(auth, 0, answer, pos, auth.length);116117pos += auth.length;118answer[pos++] = SEP;119120System.arraycopy(pw, 0, answer, pos, pw.length);121122clearPassword();123return answer;124}125126/**127* Determines whether this mechanism has completed.128* Plain completes after returning one response.129*130* @return true if has completed; false otherwise;131*/132public boolean isComplete() {133return completed;134}135136/**137* Unwraps the incoming buffer.138*139* @throws SaslException Not applicable to this mechanism.140*/141public byte[] unwrap(byte[] incoming, int offset, int len)142throws SaslException {143if (completed) {144throw new SaslException(145"PLAIN supports neither integrity nor privacy");146} else {147throw new IllegalStateException("PLAIN authentication not completed");148}149}150151/**152* Wraps the outgoing buffer.153*154* @throws SaslException Not applicable to this mechanism.155*/156public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException {157if (completed) {158throw new SaslException(159"PLAIN supports neither integrity nor privacy");160} else {161throw new IllegalStateException("PLAIN authentication not completed");162}163}164165/**166* Retrieves the negotiated property.167* This method can be called only after the authentication exchange has168* completed (i.e., when {@code isComplete()} returns true); otherwise, a169* {@code SaslException} is thrown.170*171* @return value of property; only QOP is applicable to PLAIN.172* @exception IllegalStateException if this authentication exchange173* has not completed174*/175public Object getNegotiatedProperty(String propName) {176if (completed) {177if (propName.equals(Sasl.QOP)) {178return "auth";179} else {180return null;181}182} else {183throw new IllegalStateException("PLAIN authentication not completed");184}185}186187private void clearPassword() {188if (pw != null) {189// zero out password190for (int i = 0; i < pw.length; i++) {191pw[i] = (byte)0;192}193pw = null;194}195}196197@SuppressWarnings("deprecation")198protected void finalize() {199clearPassword();200}201}202203204