001/** 002 * 003 * Copyright 2014 Florian Schmaus 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.jivesoftware.smack.sasl.packet; 018 019import java.util.Map; 020 021import org.jivesoftware.smack.packet.AbstractError; 022import org.jivesoftware.smack.packet.PlainStreamElement; 023import org.jivesoftware.smack.sasl.SASLError; 024import org.jivesoftware.smack.util.Objects; 025import org.jivesoftware.smack.util.StringUtils; 026import org.jivesoftware.smack.util.XmlStringBuilder; 027 028public class SaslStreamElements { 029 public static final String NAMESPACE = "urn:ietf:params:xml:ns:xmpp-sasl"; 030 031 /** 032 * Initiating SASL authentication by select a mechanism. 033 */ 034 public static class AuthMechanism implements PlainStreamElement { 035 public static final String ELEMENT = "auth"; 036 037 private final String mechanism; 038 private final String authenticationText; 039 040 public AuthMechanism(String mechanism, String authenticationText) { 041 this.mechanism = Objects.requireNonNull(mechanism, "SASL mechanism shouldn't be null."); 042 this.authenticationText = StringUtils.requireNotNullOrEmpty(authenticationText, 043 "SASL authenticationText must not be null or empty (RFC6120 6.4.2)"); 044 } 045 046 @Override 047 public XmlStringBuilder toXML() { 048 XmlStringBuilder xml = new XmlStringBuilder(); 049 xml.halfOpenElement(ELEMENT).xmlnsAttribute(NAMESPACE).attribute("mechanism", mechanism).rightAngleBracket(); 050 xml.optAppend(authenticationText); 051 xml.closeElement(ELEMENT); 052 return xml; 053 } 054 055 public String getMechanism() { 056 return mechanism; 057 } 058 059 public String getAuthenticationText() { 060 return authenticationText; 061 } 062 } 063 064 /** 065 * A SASL challenge stream element. 066 */ 067 public static class Challenge implements PlainStreamElement { 068 public static final String ELEMENT = "challenge"; 069 070 private final String data; 071 072 public Challenge(String data) { 073 this.data = StringUtils.returnIfNotEmptyTrimmed(data); 074 } 075 076 @Override 077 public XmlStringBuilder toXML() { 078 XmlStringBuilder xml = new XmlStringBuilder().halfOpenElement(ELEMENT).xmlnsAttribute( 079 NAMESPACE).rightAngleBracket(); 080 xml.optAppend(data); 081 xml.closeElement(ELEMENT); 082 return xml; 083 } 084 } 085 086 /** 087 * A SASL response stream element. 088 */ 089 public static class Response implements PlainStreamElement { 090 public static final String ELEMENT = "response"; 091 092 private final String authenticationText; 093 094 public Response() { 095 authenticationText = null; 096 } 097 098 public Response(String authenticationText) { 099 this.authenticationText = StringUtils.returnIfNotEmptyTrimmed(authenticationText); 100 } 101 102 @Override 103 public XmlStringBuilder toXML() { 104 XmlStringBuilder xml = new XmlStringBuilder(); 105 xml.halfOpenElement(ELEMENT).xmlnsAttribute(NAMESPACE).rightAngleBracket(); 106 xml.optAppend(authenticationText); 107 xml.closeElement(ELEMENT); 108 return xml; 109 } 110 111 public String getAuthenticationText() { 112 return authenticationText; 113 } 114 } 115 116 /** 117 * A SASL success stream element. 118 */ 119 public static class Success implements PlainStreamElement { 120 public static final String ELEMENT = "success"; 121 122 final private String data; 123 124 /** 125 * Construct a new SASL success stream element with optional additional data for the SASL layer 126 * (RFC6120 6.3.10) 127 * 128 * @param data additional data for the SASL layer or <code>null</code> 129 */ 130 public Success(String data) { 131 this.data = StringUtils.returnIfNotEmptyTrimmed(data); 132 } 133 134 /** 135 * Returns additional data for the SASL layer or <code>null</code>. 136 * 137 * @return additional data or <code>null</code> 138 */ 139 public String getData() { 140 return data; 141 } 142 143 @Override 144 public XmlStringBuilder toXML() { 145 XmlStringBuilder xml = new XmlStringBuilder(); 146 xml.halfOpenElement(ELEMENT).xmlnsAttribute(NAMESPACE).rightAngleBracket(); 147 xml.optAppend(data); 148 xml.closeElement(ELEMENT); 149 return xml; 150 } 151 } 152 153 /** 154 * A SASL failure stream element, also called "SASL Error" 155 * @see <a href="http://xmpp.org/rfcs/rfc6120.html#sasl-errors">RFC 6120 6.5 SASL Errors</a> 156 */ 157 public static class SASLFailure extends AbstractError implements PlainStreamElement { 158 public static final String ELEMENT = "failure"; 159 160 private final SASLError saslError; 161 private final String saslErrorString; 162 163 public SASLFailure(String saslError) { 164 this(saslError, null); 165 } 166 167 public SASLFailure(String saslError, Map<String, String> descriptiveTexts) { 168 super(descriptiveTexts); 169 SASLError error = SASLError.fromString(saslError); 170 if (error == null) { 171 // RFC6120 6.5 states that unknown condition must be treat as generic authentication 172 // failure. 173 this.saslError = SASLError.not_authorized; 174 } 175 else { 176 this.saslError = error; 177 } 178 this.saslErrorString = saslError; 179 } 180 181 /** 182 * Get the SASL related error condition. 183 * 184 * @return the SASL related error condition. 185 */ 186 public SASLError getSASLError() { 187 return saslError; 188 } 189 190 /** 191 * @return the SASL error as String 192 */ 193 public String getSASLErrorString() { 194 return saslErrorString; 195 } 196 197 @Override 198 public XmlStringBuilder toXML() { 199 XmlStringBuilder xml = new XmlStringBuilder(); 200 xml.halfOpenElement(ELEMENT).xmlnsAttribute(NAMESPACE).rightAngleBracket(); 201 xml.emptyElement(saslErrorString); 202 addDescriptiveTextsAndExtensions(xml); 203 xml.closeElement(ELEMENT); 204 return xml; 205 } 206 207 @Override 208 public String toString() { 209 return toXML().toString(); 210 } 211 } 212}