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.Nonza; 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 Nonza { 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 @Override 064 public String getNamespace() { 065 return NAMESPACE; 066 } 067 068 @Override 069 public String getElementName() { 070 return ELEMENT; 071 } 072 } 073 074 /** 075 * A SASL challenge stream element. 076 */ 077 public static class Challenge implements Nonza { 078 public static final String ELEMENT = "challenge"; 079 080 private final String data; 081 082 public Challenge(String data) { 083 this.data = StringUtils.returnIfNotEmptyTrimmed(data); 084 } 085 086 @Override 087 public XmlStringBuilder toXML() { 088 XmlStringBuilder xml = new XmlStringBuilder().halfOpenElement(ELEMENT).xmlnsAttribute( 089 NAMESPACE).rightAngleBracket(); 090 xml.optAppend(data); 091 xml.closeElement(ELEMENT); 092 return xml; 093 } 094 095 @Override 096 public String getNamespace() { 097 return NAMESPACE; 098 } 099 100 @Override 101 public String getElementName() { 102 return ELEMENT; 103 } 104 } 105 106 /** 107 * A SASL response stream element. 108 */ 109 public static class Response implements Nonza { 110 public static final String ELEMENT = "response"; 111 112 private final String authenticationText; 113 114 public Response() { 115 authenticationText = null; 116 } 117 118 public Response(String authenticationText) { 119 this.authenticationText = StringUtils.returnIfNotEmptyTrimmed(authenticationText); 120 } 121 122 @Override 123 public XmlStringBuilder toXML() { 124 XmlStringBuilder xml = new XmlStringBuilder(); 125 xml.halfOpenElement(ELEMENT).xmlnsAttribute(NAMESPACE).rightAngleBracket(); 126 xml.optAppend(authenticationText); 127 xml.closeElement(ELEMENT); 128 return xml; 129 } 130 131 public String getAuthenticationText() { 132 return authenticationText; 133 } 134 135 @Override 136 public String getNamespace() { 137 return NAMESPACE; 138 } 139 140 @Override 141 public String getElementName() { 142 return ELEMENT; 143 } 144 } 145 146 /** 147 * A SASL success stream element. 148 */ 149 public static class Success implements Nonza { 150 public static final String ELEMENT = "success"; 151 152 final private String data; 153 154 /** 155 * Construct a new SASL success stream element with optional additional data for the SASL layer. 156 * (RFC6120 6.3.10) 157 * 158 * @param data additional data for the SASL layer or <code>null</code> 159 */ 160 public Success(String data) { 161 this.data = StringUtils.returnIfNotEmptyTrimmed(data); 162 } 163 164 /** 165 * Returns additional data for the SASL layer or <code>null</code>. 166 * 167 * @return additional data or <code>null</code> 168 */ 169 public String getData() { 170 return data; 171 } 172 173 @Override 174 public XmlStringBuilder toXML() { 175 XmlStringBuilder xml = new XmlStringBuilder(); 176 xml.halfOpenElement(ELEMENT).xmlnsAttribute(NAMESPACE).rightAngleBracket(); 177 xml.optAppend(data); 178 xml.closeElement(ELEMENT); 179 return xml; 180 } 181 182 @Override 183 public String getNamespace() { 184 return NAMESPACE; 185 } 186 187 @Override 188 public String getElementName() { 189 return ELEMENT; 190 } 191 } 192 193 /** 194 * A SASL failure stream element, also called "SASL Error". 195 * @see <a href="http://xmpp.org/rfcs/rfc6120.html#sasl-errors">RFC 6120 6.5 SASL Errors</a> 196 */ 197 public static class SASLFailure extends AbstractError implements Nonza { 198 public static final String ELEMENT = "failure"; 199 200 private final SASLError saslError; 201 private final String saslErrorString; 202 203 public SASLFailure(String saslError) { 204 this(saslError, null); 205 } 206 207 public SASLFailure(String saslError, Map<String, String> descriptiveTexts) { 208 super(descriptiveTexts); 209 SASLError error = SASLError.fromString(saslError); 210 if (error == null) { 211 // RFC6120 6.5 states that unknown condition must be treat as generic authentication 212 // failure. 213 this.saslError = SASLError.not_authorized; 214 } 215 else { 216 this.saslError = error; 217 } 218 this.saslErrorString = saslError; 219 } 220 221 /** 222 * Get the SASL related error condition. 223 * 224 * @return the SASL related error condition. 225 */ 226 public SASLError getSASLError() { 227 return saslError; 228 } 229 230 /** 231 * Get the SASL error as String. 232 * @return the SASL error as String 233 */ 234 public String getSASLErrorString() { 235 return saslErrorString; 236 } 237 238 @Override 239 public XmlStringBuilder toXML() { 240 XmlStringBuilder xml = new XmlStringBuilder(); 241 xml.halfOpenElement(ELEMENT).xmlnsAttribute(NAMESPACE).rightAngleBracket(); 242 xml.emptyElement(saslErrorString); 243 addDescriptiveTextsAndExtensions(xml); 244 xml.closeElement(ELEMENT); 245 return xml; 246 } 247 248 @Override 249 public String toString() { 250 return toXML().toString(); 251 } 252 253 @Override 254 public String getNamespace() { 255 return NAMESPACE; 256 } 257 258 @Override 259 public String getElementName() { 260 return ELEMENT; 261 } 262 } 263}