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.javax; 018 019import java.io.IOException; 020import java.util.HashMap; 021import java.util.Map; 022 023import javax.security.auth.callback.Callback; 024import javax.security.auth.callback.CallbackHandler; 025import javax.security.auth.callback.NameCallback; 026import javax.security.auth.callback.PasswordCallback; 027import javax.security.auth.callback.UnsupportedCallbackException; 028import javax.security.sasl.RealmCallback; 029import javax.security.sasl.RealmChoiceCallback; 030import javax.security.sasl.Sasl; 031import javax.security.sasl.SaslClient; 032import javax.security.sasl.SaslException; 033 034import org.jivesoftware.smack.SmackException; 035import org.jivesoftware.smack.sasl.SASLMechanism; 036 037public abstract class SASLJavaXMechanism extends SASLMechanism { 038 039 protected SaslClient sc; 040 041 @Override 042 public abstract String getName(); 043 044 @Override 045 public final void checkIfSuccessfulOrThrow() throws SmackException { 046 if (!sc.isComplete()) { 047 throw new SmackException(getName() + " was not completed"); 048 } 049 } 050 051 @Override 052 protected void authenticateInternal() 053 throws SmackException { 054 String[] mechanisms = { getName() }; 055 Map<String, String> props = getSaslProps(); 056 try { 057 sc = Sasl.createSaslClient(mechanisms, null, "xmpp", getServerName(), props, 058 new CallbackHandler() { 059 @Override 060 public void handle(Callback[] callbacks) throws IOException, 061 UnsupportedCallbackException { 062 for (int i = 0; i < callbacks.length; i++) { 063 if (callbacks[i] instanceof NameCallback) { 064 NameCallback ncb = (NameCallback) callbacks[i]; 065 ncb.setName(authenticationId); 066 } 067 else if (callbacks[i] instanceof PasswordCallback) { 068 PasswordCallback pcb = (PasswordCallback) callbacks[i]; 069 pcb.setPassword(password.toCharArray()); 070 } 071 else if (callbacks[i] instanceof RealmCallback) { 072 RealmCallback rcb = (RealmCallback) callbacks[i]; 073 // Retrieve the REALM from the challenge response that 074 // the server returned when the client initiated the 075 // authentication exchange. If this value is not null or 076 // empty, *this value* has to be sent back to the server 077 // in the client's response to the server's challenge 078 String text = rcb.getDefaultText(); 079 // The SASL client (sc) created in smack uses 080 // rcb.getText when creating the negotiatedRealm to send 081 // it back to the server. Make sure that this value 082 // matches the server's realm 083 rcb.setText(text); 084 } 085 else if (callbacks[i] instanceof RealmChoiceCallback) { 086 // unused, prevents UnsupportedCallbackException 087 // RealmChoiceCallback rccb = 088 // (RealmChoiceCallback)callbacks[i]; 089 } 090 else { 091 throw new UnsupportedCallbackException(callbacks[i]); 092 } 093 } 094 } 095 096 }); 097 } 098 catch (SaslException e) { 099 throw new SmackException(e); 100 } 101 } 102 103 @Override 104 protected void authenticateInternal(CallbackHandler cbh) 105 throws SmackException { 106 String[] mechanisms = { getName() }; 107 Map<String, String> props = getSaslProps(); 108 try { 109 sc = Sasl.createSaslClient(mechanisms, null, "xmpp", host, props, cbh); 110 } 111 catch (SaslException e) { 112 throw new SmackException(e); 113 } 114 } 115 116 @Override 117 protected byte[] getAuthenticationText() throws SmackException { 118 if (sc.hasInitialResponse()) { 119 try { 120 return sc.evaluateChallenge(new byte[0]); 121 } 122 catch (SaslException e) { 123 throw new SmackException(e); 124 } 125 } 126 return null; 127 } 128 129 @Override 130 protected byte[] evaluateChallenge(byte[] challenge) throws SmackException { 131 try { 132 if (challenge != null) { 133 return sc.evaluateChallenge(challenge); 134 } 135 else { 136 return sc.evaluateChallenge(new byte[0]); 137 } 138 } 139 catch (SaslException e) { 140 throw new SmackException(e); 141 } 142 } 143 144 protected Map<String,String> getSaslProps() { 145 return new HashMap<String, String>(); 146 } 147 148 protected String getServerName() { 149 return serviceName; 150 } 151}