View | Details | Return to bug 26067 | Differences between
and this patch

Collapse All | Expand All

(-)AuthInfo.java (-27 / +13 lines)
Lines 56-65 Link Here
56
 */
56
 */
57
public class AuthInfo
57
public class AuthInfo
58
{
58
{
59
60
  // Constants and variables
61
  // -------------------------------------------------------------------------
62
63
  private static final ArrayList factories = new ArrayList();
59
  private static final ArrayList factories = new ArrayList();
64
  static
60
  static
65
    {
61
    {
Lines 72-85 Link Here
72
        {
68
        {
73
          for (StringTokenizer st = new StringTokenizer(pkgs, "|"); st.hasMoreTokens();)
69
          for (StringTokenizer st = new StringTokenizer(pkgs, "|"); st.hasMoreTokens();)
74
            {
70
            {
75
              clazz = st.nextToken();
71
              clazz = st.nextToken().trim();
76
              if (!"gnu.crypto.sasl".equals(clazz))
72
              if (! "gnu.javax.crypto.sasl".equals(clazz))
77
                {
73
                {
78
                  clazz += ".AuthInfoProviderFactory";
74
                  clazz += ".AuthInfoProviderFactory";
79
                  try
75
                  try
80
                    {
76
                    {
81
                      IAuthInfoProviderFactory factory = (IAuthInfoProviderFactory) Class.forName(
77
                      IAuthInfoProviderFactory factory =
82
                                                                                                  clazz).newInstance();
78
                          (IAuthInfoProviderFactory) Class.forName(clazz).newInstance();
83
                      factories.add(factory);
79
                      factories.add(factory);
84
                    }
80
                    }
85
                  catch (ClassCastException ignored)
81
                  catch (ClassCastException ignored)
Lines 99-131 Link Here
99
        }
95
        }
100
      // always add ours last; unless it's already there
96
      // always add ours last; unless it's already there
101
      if (!factories.contains(ours))
97
      if (!factories.contains(ours))
102
        {
98
        factories.add(ours);
103
          factories.add(ours);
104
        }
105
    }
99
    }
106
100
107
  // Constructor(s)
108
  // -------------------------------------------------------------------------
109
110
  /** Trivial constructor to enforce Singleton pattern. */
101
  /** Trivial constructor to enforce Singleton pattern. */
111
  private AuthInfo()
102
  private AuthInfo()
112
  {
103
  {
113
    super();
104
    super();
114
  }
105
  }
115
106
116
  // Class methods
117
  // -------------------------------------------------------------------------
118
119
  /**
107
  /**
120
   * A convenience method to return the authentication information provider
108
   * A convenience method to return the authentication information provider for
121
   * for a designated SASL mechnanism. It goes through all the installed
109
   * a designated SASL mechnanism. It goes through all the installed provider
122
   * provider factories, one at a time, and attempts to return a new instance
110
   * factories, one at a time, and attempts to return a new instance of the
123
   * of the provider for the designated mechanism. It stops at the first
111
   * provider for the designated mechanism. It stops at the first factory
124
   * factory returning a non-null provider.
112
   * returning a non-null provider.
125
   *
113
   * 
126
   * @param mechanism the name of a SASL mechanism.
114
   * @param mechanism the name of a SASL mechanism.
127
   * @return an implementation that provides {@link IAuthInfoProvider} for that
115
   * @return an implementation that provides {@link IAuthInfoProvider} for that
128
   * mechanism; or <code>null</code> if none found.
116
   *         mechanism; or <code>null</code> if none found.
129
   */
117
   */
130
  public static IAuthInfoProvider getProvider(String mechanism)
118
  public static IAuthInfoProvider getProvider(String mechanism)
131
  {
119
  {
Lines 134-142 Link Here
134
        IAuthInfoProviderFactory factory = (IAuthInfoProviderFactory) it.next();
122
        IAuthInfoProviderFactory factory = (IAuthInfoProviderFactory) it.next();
135
        IAuthInfoProvider result = factory.getInstance(mechanism);
123
        IAuthInfoProvider result = factory.getInstance(mechanism);
136
        if (result != null)
124
        if (result != null)
137
          {
125
          return result;
138
            return result;
139
          }
140
      }
126
      }
141
    return null;
127
    return null;
142
  }
128
  }
(-)AuthInfoProviderFactory.java (-28 / +6 lines)
Lines 46-89 Link Here
46
/**
46
/**
47
 * The concrete SASL authentication information provider factory.
47
 * The concrete SASL authentication information provider factory.
48
 */
48
 */
49
public class AuthInfoProviderFactory implements IAuthInfoProviderFactory
49
public class AuthInfoProviderFactory
50
    implements IAuthInfoProviderFactory
50
{
51
{
51
52
  // Constants and variables
53
  // -------------------------------------------------------------------------
54
55
  // Constructor(s)
56
  // -------------------------------------------------------------------------
57
58
  // implicit 0-args constructor
52
  // implicit 0-args constructor
59
53
60
  // Class methods
61
  // -------------------------------------------------------------------------
62
63
  // Instance methods
64
  // -------------------------------------------------------------------------
65
66
  // IAuthInfoProviderFactory interface implementation -----------------------
67
68
  public IAuthInfoProvider getInstance(String mechanism)
54
  public IAuthInfoProvider getInstance(String mechanism)
69
  {
55
  {
70
    if (mechanism == null)
56
    if (mechanism == null)
71
      {
57
      return null;
72
        return null;
73
      }
74
    mechanism = mechanism.trim().toUpperCase();
58
    mechanism = mechanism.trim().toUpperCase();
75
    if (mechanism.startsWith(Registry.SASL_SRP_MECHANISM))
59
    if (mechanism.startsWith(Registry.SASL_SRP_MECHANISM))
76
      {
60
      return new SRPAuthInfoProvider();
77
        return new SRPAuthInfoProvider();
78
      }
79
    if (mechanism.equals(Registry.SASL_CRAM_MD5_MECHANISM))
61
    if (mechanism.equals(Registry.SASL_CRAM_MD5_MECHANISM))
80
      {
62
      return new CramMD5AuthInfoProvider();
81
        return new CramMD5AuthInfoProvider();
82
      }
83
    if (mechanism.equals(Registry.SASL_PLAIN_MECHANISM))
63
    if (mechanism.equals(Registry.SASL_PLAIN_MECHANISM))
84
      {
64
      return new PlainAuthInfoProvider();
85
        return new PlainAuthInfoProvider();
86
      }
87
    return null;
65
    return null;
88
  }
66
  }
89
}
67
}
(-)ClientFactory.java (-64 / +22 lines)
Lines 47-57 Link Here
47
import java.util.ArrayList;
47
import java.util.ArrayList;
48
import java.util.Arrays;
48
import java.util.Arrays;
49
import java.util.Collections;
49
import java.util.Collections;
50
import java.util.HashMap;
50
import java.util.HashSet;
51
import java.util.HashSet;
51
import java.util.List;
52
import java.util.List;
52
import java.util.Map;
53
import java.util.Map;
53
import java.util.Set;
54
import java.util.Set;
54
import java.util.HashMap;
55
55
56
import javax.security.auth.callback.CallbackHandler;
56
import javax.security.auth.callback.CallbackHandler;
57
import javax.security.sasl.Sasl;
57
import javax.security.sasl.Sasl;
Lines 62-114 Link Here
62
/**
62
/**
63
 * The implementation of {@link SaslClientFactory}.
63
 * The implementation of {@link SaslClientFactory}.
64
 */
64
 */
65
public class ClientFactory implements SaslClientFactory
65
public class ClientFactory
66
    implements SaslClientFactory
66
{
67
{
67
68
  // Constants and variables
69
  // -------------------------------------------------------------------------
70
71
  // Constructor(s)
72
  // -------------------------------------------------------------------------
73
74
  // implicit 0-arguments constructor
68
  // implicit 0-arguments constructor
75
69
76
  // Class methods
77
  // -------------------------------------------------------------------------
78
79
  public static final Set getNames()
70
  public static final Set getNames()
80
  {
71
  {
81
    return Collections.unmodifiableSet(new HashSet(
72
    return Collections.unmodifiableSet(new HashSet(Arrays.asList(getNamesInternal(null))));
82
                                                   Arrays.asList(getNamesInternal(null))));
83
  }
73
  }
84
74
85
  private static final String[] getNamesInternal(Map props)
75
  private static final String[] getNamesInternal(Map props)
86
  {
76
  {
87
    String[] all = new String[] { Registry.SASL_SRP_MECHANISM,
77
    String[] all = new String[] {
88
                                 Registry.SASL_CRAM_MD5_MECHANISM,
78
        Registry.SASL_SRP_MECHANISM,
89
                                 Registry.SASL_PLAIN_MECHANISM,
79
        Registry.SASL_CRAM_MD5_MECHANISM,
90
                                 Registry.SASL_ANONYMOUS_MECHANISM };
80
        Registry.SASL_PLAIN_MECHANISM,
91
81
        Registry.SASL_ANONYMOUS_MECHANISM };
92
    if (props == null)
82
    if (props == null)
93
      {
83
      return all;
94
        return all;
95
      }
96
    if (hasPolicy(Sasl.POLICY_PASS_CREDENTIALS, props))
84
    if (hasPolicy(Sasl.POLICY_PASS_CREDENTIALS, props))
97
      {
85
      return new String[0];
98
        return new String[0];
99
      }
100
101
    List result = new ArrayList(all.length);
86
    List result = new ArrayList(all.length);
102
    ;
103
    for (int i = 0; i < all.length;)
87
    for (int i = 0; i < all.length;)
104
      {
88
      result.add(all[i++]);
105
        result.add(all[i++]);
106
      }
107
108
    if (hasPolicy(Sasl.POLICY_NOPLAINTEXT, props))
89
    if (hasPolicy(Sasl.POLICY_NOPLAINTEXT, props))
109
      {
90
      result.remove(Registry.SASL_PLAIN_MECHANISM);
110
        result.remove(Registry.SASL_PLAIN_MECHANISM);
111
      }
112
    if (hasPolicy(Sasl.POLICY_NOACTIVE, props))
91
    if (hasPolicy(Sasl.POLICY_NOACTIVE, props))
113
      {
92
      {
114
        result.remove(Registry.SASL_CRAM_MD5_MECHANISM);
93
        result.remove(Registry.SASL_CRAM_MD5_MECHANISM);
Lines 135-166 Link Here
135
  public static final ClientMechanism getInstance(String mechanism)
114
  public static final ClientMechanism getInstance(String mechanism)
136
  {
115
  {
137
    if (mechanism == null)
116
    if (mechanism == null)
138
      {
117
      return null;
139
        return null;
140
      }
141
    mechanism = mechanism.trim().toUpperCase();
118
    mechanism = mechanism.trim().toUpperCase();
142
    if (mechanism.equals(Registry.SASL_SRP_MECHANISM))
119
    if (mechanism.equals(Registry.SASL_SRP_MECHANISM))
143
      {
120
      return new SRPClient();
144
        return new SRPClient();
145
      }
146
    if (mechanism.equals(Registry.SASL_CRAM_MD5_MECHANISM))
121
    if (mechanism.equals(Registry.SASL_CRAM_MD5_MECHANISM))
147
      {
122
      return new CramMD5Client();
148
        return new CramMD5Client();
149
      }
150
    if (mechanism.equals(Registry.SASL_PLAIN_MECHANISM))
123
    if (mechanism.equals(Registry.SASL_PLAIN_MECHANISM))
151
      {
124
      return new PlainClient();
152
        return new PlainClient();
153
      }
154
    if (mechanism.equals(Registry.SASL_ANONYMOUS_MECHANISM))
125
    if (mechanism.equals(Registry.SASL_ANONYMOUS_MECHANISM))
155
      {
126
      return new AnonymousClient();
156
        return new AnonymousClient();
157
      }
158
    return null;
127
    return null;
159
  }
128
  }
160
129
161
  // Instance methods
162
  // -------------------------------------------------------------------------
163
164
  public SaslClient createSaslClient(String[] mechanisms,
130
  public SaslClient createSaslClient(String[] mechanisms,
165
                                     String authorisationID, String protocol,
131
                                     String authorisationID, String protocol,
166
                                     String serverName, Map props,
132
                                     String serverName, Map props,
Lines 173-201 Link Here
173
        mechanism = mechanisms[i];
139
        mechanism = mechanisms[i];
174
        result = getInstance(mechanism);
140
        result = getInstance(mechanism);
175
        if (result != null)
141
        if (result != null)
176
          {
142
          break;
177
            break;
178
          }
179
      }
143
      }
180
181
    if (result != null)
144
    if (result != null)
182
      {
145
      {
183
        HashMap attributes = new HashMap();
146
        HashMap attributes = new HashMap();
184
        if (props != null)
147
        if (props != null)
185
          {
148
          attributes.putAll(props);
186
            attributes.putAll(props);
187
          }
188
        attributes.put(Registry.SASL_AUTHORISATION_ID, authorisationID);
149
        attributes.put(Registry.SASL_AUTHORISATION_ID, authorisationID);
189
        attributes.put(Registry.SASL_PROTOCOL, protocol);
150
        attributes.put(Registry.SASL_PROTOCOL, protocol);
190
        attributes.put(Registry.SASL_SERVER_NAME, serverName);
151
        attributes.put(Registry.SASL_SERVER_NAME, serverName);
191
        attributes.put(Registry.SASL_CALLBACK_HANDLER, cbh);
152
        attributes.put(Registry.SASL_CALLBACK_HANDLER, cbh);
192
193
        result.init(attributes);
153
        result.init(attributes);
194
        return result;
154
        return result;
195
      }
155
      }
196
156
    throw new SaslException("No supported mechanism found in given mechanism list");
197
    throw new SaslException(
198
                            "No supported mechanism found in given mechanism list");
199
  }
157
  }
200
158
201
  public String[] getMechanismNames(Map props)
159
  public String[] getMechanismNames(Map props)
Lines 207-210 Link Here
207
  {
165
  {
208
    return "true".equalsIgnoreCase(String.valueOf(props.get(propertyName)));
166
    return "true".equalsIgnoreCase(String.valueOf(props.get(propertyName)));
209
  }
167
  }
210
}
168
}
(-)ClientMechanism.java (-111 / +39 lines)
Lines 42-91 Link Here
42
42
43
import java.util.HashMap;
43
import java.util.HashMap;
44
import java.util.Map;
44
import java.util.Map;
45
45
import javax.security.auth.callback.CallbackHandler;
46
import javax.security.auth.callback.CallbackHandler;
46
import javax.security.sasl.Sasl;
47
import javax.security.sasl.Sasl;
47
import javax.security.sasl.SaslClient;
48
import javax.security.sasl.SaslClient;
48
import javax.security.sasl.SaslException;
49
import javax.security.sasl.SaslException;
49
50
50
/**
51
/**
51
 * <p>A base class to facilitate implementing SASL client-side mechanisms.</p>
52
 * A base class to facilitate implementing SASL client-side mechanisms.
52
 */
53
 */
53
public abstract class ClientMechanism implements SaslClient
54
public abstract class ClientMechanism
55
    implements SaslClient
54
{
56
{
55
56
  // Constants and variables
57
  // -------------------------------------------------------------------------
58
59
  /** Name of this mechanism. */
57
  /** Name of this mechanism. */
60
  protected String mechanism;
58
  protected String mechanism;
61
62
  /** The authorisation identity. */
59
  /** The authorisation identity. */
63
  protected String authorizationID;
60
  protected String authorizationID;
64
65
  /** Name of protocol using this mechanism. */
61
  /** Name of protocol using this mechanism. */
66
  protected String protocol;
62
  protected String protocol;
67
68
  /** Name of server to authenticate to. */
63
  /** Name of server to authenticate to. */
69
  protected String serverName;
64
  protected String serverName;
70
71
  /** Properties of qualities desired for this mechanism. */
65
  /** Properties of qualities desired for this mechanism. */
72
  protected Map properties;
66
  protected Map properties;
73
74
  /** Callback handler to use with this mechanism instance. */
67
  /** Callback handler to use with this mechanism instance. */
75
  protected CallbackHandler handler;
68
  protected CallbackHandler handler;
76
77
  /** Channel binding data to use with this mechanism instance. */
69
  /** Channel binding data to use with this mechanism instance. */
78
  protected byte[] channelBinding;
70
  protected byte[] channelBinding;
79
80
  /** Whether authentication phase is completed (true) or not (false). */
71
  /** Whether authentication phase is completed (true) or not (false). */
81
  protected boolean complete = false;
72
  protected boolean complete = false;
82
83
  /** The state of the authentication automaton. */
73
  /** The state of the authentication automaton. */
84
  protected int state = -1;
74
  protected int state = -1;
85
75
86
  // Constructor(s)
87
  // -------------------------------------------------------------------------
88
89
  protected ClientMechanism(final String mechanism)
76
  protected ClientMechanism(final String mechanism)
90
  {
77
  {
91
    super();
78
    super();
Lines 94-113 Link Here
94
    this.state = -1;
81
    this.state = -1;
95
  }
82
  }
96
83
97
  // Class methods
98
  // -------------------------------------------------------------------------
99
100
  // Instance methods
101
  // -------------------------------------------------------------------------
102
103
  // abstract methods to be implemented by concrete subclasses ---------------
104
105
  protected abstract void initMechanism() throws SaslException;
84
  protected abstract void initMechanism() throws SaslException;
106
85
107
  protected abstract void resetMechanism() throws SaslException;
86
  protected abstract void resetMechanism() throws SaslException;
108
87
109
  // javax.security.sasl.SaslClient interface implementation -----------------
110
111
  public abstract byte[] evaluateChallenge(byte[] challenge)
88
  public abstract byte[] evaluateChallenge(byte[] challenge)
112
      throws SaslException;
89
      throws SaslException;
113
90
Lines 121-140 Link Here
121
  public byte[] unwrap(final byte[] incoming, final int offset, final int len)
98
  public byte[] unwrap(final byte[] incoming, final int offset, final int len)
122
      throws SaslException
99
      throws SaslException
123
  {
100
  {
124
    if (!isComplete())
101
    if (! isComplete())
125
      {
102
      throw new IllegalMechanismStateException();
126
        throw new IllegalMechanismStateException();
127
      }
128
    return this.engineUnwrap(incoming, offset, len);
103
    return this.engineUnwrap(incoming, offset, len);
129
  }
104
  }
130
105
131
  public byte[] wrap(final byte[] outgoing, final int offset, final int len)
106
  public byte[] wrap(final byte[] outgoing, final int offset, final int len)
132
      throws SaslException
107
      throws SaslException
133
  {
108
  {
134
    if (!isComplete())
109
    if (! isComplete())
135
      {
110
      throw new IllegalMechanismStateException();
136
        throw new IllegalMechanismStateException();
137
      }
138
    return this.engineWrap(outgoing, offset, len);
111
    return this.engineWrap(outgoing, offset, len);
139
  }
112
  }
140
113
Lines 145-202 Link Here
145
118
146
  public Object getNegotiatedProperty(final String propName)
119
  public Object getNegotiatedProperty(final String propName)
147
  {
120
  {
148
    if (!isComplete())
121
    if (! isComplete())
149
      {
122
      throw new IllegalStateException();
150
        throw new IllegalStateException();
151
      }
152
    if (Sasl.QOP.equals(propName))
123
    if (Sasl.QOP.equals(propName))
153
      {
124
      return getNegotiatedQOP();
154
        return getNegotiatedQOP();
155
      }
156
    if (Sasl.STRENGTH.equals(propName))
125
    if (Sasl.STRENGTH.equals(propName))
157
      {
126
      return getNegotiatedStrength();
158
        return getNegotiatedStrength();
159
      }
160
    if (Sasl.SERVER_AUTH.equals(propName))
127
    if (Sasl.SERVER_AUTH.equals(propName))
161
      {
128
      return getNegotiatedServerAuth();
162
        return getNegotiatedServerAuth();
163
      }
164
    if (Sasl.MAX_BUFFER.equals(propName))
129
    if (Sasl.MAX_BUFFER.equals(propName))
165
      {
130
      return getNegotiatedMaxBuffer();
166
        return getNegotiatedMaxBuffer();
167
      }
168
    if (Sasl.RAW_SEND_SIZE.equals(propName))
131
    if (Sasl.RAW_SEND_SIZE.equals(propName))
169
      {
132
      return getNegotiatedRawSendSize();
170
        return getNegotiatedRawSendSize();
171
      }
172
    if (Sasl.POLICY_NOPLAINTEXT.equals(propName))
133
    if (Sasl.POLICY_NOPLAINTEXT.equals(propName))
173
      {
134
      return getNegotiatedPolicyNoPlainText();
174
        return getNegotiatedPolicyNoPlainText();
175
      }
176
    if (Sasl.POLICY_NOACTIVE.equals(propName))
135
    if (Sasl.POLICY_NOACTIVE.equals(propName))
177
      {
136
      return getNegotiatedPolicyNoActive();
178
        return getNegotiatedPolicyNoActive();
179
      }
180
    if (Sasl.POLICY_NODICTIONARY.equals(propName))
137
    if (Sasl.POLICY_NODICTIONARY.equals(propName))
181
      {
138
      return getNegotiatedPolicyNoDictionary();
182
        return getNegotiatedPolicyNoDictionary();
183
      }
184
    if (Sasl.POLICY_NOANONYMOUS.equals(propName))
139
    if (Sasl.POLICY_NOANONYMOUS.equals(propName))
185
      {
140
      return getNegotiatedPolicyNoAnonymous();
186
        return getNegotiatedPolicyNoAnonymous();
187
      }
188
    if (Sasl.POLICY_FORWARD_SECRECY.equals(propName))
141
    if (Sasl.POLICY_FORWARD_SECRECY.equals(propName))
189
      {
142
      return getNegotiatedPolicyForwardSecrecy();
190
        return getNegotiatedPolicyForwardSecrecy();
191
      }
192
    if (Sasl.POLICY_PASS_CREDENTIALS.equals(propName))
143
    if (Sasl.POLICY_PASS_CREDENTIALS.equals(propName))
193
      {
144
      return getNegotiatedPolicyPassCredentials();
194
        return getNegotiatedPolicyPassCredentials();
195
      }
196
    if (Sasl.REUSE.equals(propName))
145
    if (Sasl.REUSE.equals(propName))
197
      {
146
      return getReuse();
198
        return getReuse();
199
      }
200
    return null;
147
    return null;
201
  }
148
  }
202
149
Lines 204-211 Link Here
204
  {
151
  {
205
  }
152
  }
206
153
207
  // other Instance methods --------------------------------------------------
208
209
  public String getAuthorizationID()
154
  public String getAuthorizationID()
210
  {
155
  {
211
    return authorizationID;
156
    return authorizationID;
Lines 288-317 Link Here
288
  }
233
  }
289
234
290
  /**
235
  /**
291
   * <p>Initialises the mechanism with designated attributes. Permissible names
236
   * Initialises the mechanism with designated attributes. Permissible names and
292
   * and values are mechanism specific.</p>
237
   * values are mechanism specific.
293
   *
238
   * 
294
   * @param attributes a set of name-value pairs that describes the desired
239
   * @param attributes a set of name-value pairs that describes the desired
295
   * future behaviour of this instance.
240
   *          future behaviour of this instance.
296
   * @throws IllegalMechanismStateException if the instance is already
241
   * @throws IllegalMechanismStateException if the instance is already
297
   * initialised.
242
   *           initialised.
298
   * @throws SaslException if an exception occurs during the process.
243
   * @throws SaslException if an exception occurs during the process.
299
   */
244
   */
300
  public void init(final Map attributes) throws SaslException
245
  public void init(final Map attributes) throws SaslException
301
  {
246
  {
302
    if (state != -1)
247
    if (state != -1)
303
      {
248
      throw new IllegalMechanismStateException("init()");
304
        throw new IllegalMechanismStateException("init()");
305
      }
306
307
    if (properties == null)
249
    if (properties == null)
308
      {
250
      properties = new HashMap();
309
        properties = new HashMap();
310
      }
311
    else
251
    else
312
      {
252
      properties.clear();
313
        properties.clear();
314
      }
315
    if (attributes != null)
253
    if (attributes != null)
316
      {
254
      {
317
        authorizationID = (String) attributes.get(Registry.SASL_AUTHORISATION_ID);
255
        authorizationID = (String) attributes.get(Registry.SASL_AUTHORISATION_ID);
Lines 322-356 Link Here
322
        properties.putAll(attributes);
260
        properties.putAll(attributes);
323
      }
261
      }
324
    else
262
    else
325
      {
263
      handler = null;
326
        handler = null;
327
      }
328
264
329
    if (authorizationID == null)
265
    if (authorizationID == null)
330
      {
266
      authorizationID = "";
331
        authorizationID = "";
332
      }
333
    if (protocol == null)
267
    if (protocol == null)
334
      {
268
      protocol = "";
335
        protocol = "";
336
      }
337
    if (serverName == null)
269
    if (serverName == null)
338
      {
270
      serverName = "";
339
        serverName = "";
340
      }
341
    if (channelBinding == null)
271
    if (channelBinding == null)
342
      {
272
      channelBinding = new byte[0];
343
        channelBinding = new byte[0];
344
      }
345
    initMechanism();
273
    initMechanism();
346
    complete = false;
274
    complete = false;
347
    state = 0;
275
    state = 0;
348
  }
276
  }
349
277
350
  /**
278
  /**
351
   * <p>Resets the mechanism instance for re-initialisation and use with other
279
   * Resets the mechanism instance for re-initialisation and use with other
352
   * characteristics.</p>
280
   * characteristics.
353
   *
281
   * 
354
   * @throws SaslException if an exception occurs during the process.
282
   * @throws SaslException if an exception occurs during the process.
355
   */
283
   */
356
  public void reset() throws SaslException
284
  public void reset() throws SaslException
Lines 362-365 Link Here
362
    complete = false;
290
    complete = false;
363
    state = -1;
291
    state = -1;
364
  }
292
  }
365
}
293
}
(-)ConfidentialityException.java (-6 / +6 lines)
Lines 45-56 Link Here
45
 * exception is thrown to indicate that a violation has occured during the
45
 * exception is thrown to indicate that a violation has occured during the
46
 * processing of a <i>confidentiality</i> protection filter.
46
 * processing of a <i>confidentiality</i> protection filter.
47
 */
47
 */
48
public class ConfidentialityException extends SaslException
48
public class ConfidentialityException
49
    extends SaslException
49
{
50
{
50
51
  /**
51
  /**
52
   * Constructs a new instance of <code>ConfidentialityException</code> with no
52
   * Constructs a new instance of <code>ConfidentialityException</code> with
53
   * detail message.
53
   * no detail message.
54
   */
54
   */
55
  public ConfidentialityException()
55
  public ConfidentialityException()
56
  {
56
  {
Lines 60-66 Link Here
60
  /**
60
  /**
61
   * Constructs a new instance of <code>ConfidentialityException</code> with
61
   * Constructs a new instance of <code>ConfidentialityException</code> with
62
   * the specified detail message.
62
   * the specified detail message.
63
   *
63
   * 
64
   * @param s the detail message.
64
   * @param s the detail message.
65
   */
65
   */
66
  public ConfidentialityException(String s)
66
  public ConfidentialityException(String s)
Lines 71-77 Link Here
71
  /**
71
  /**
72
   * Constructs a new instance of <code>ConfidentialityException</code> with a
72
   * Constructs a new instance of <code>ConfidentialityException</code> with a
73
   * detailed message and a root exception.
73
   * detailed message and a root exception.
74
   *
74
   * 
75
   * @param s possibly null additional detail about the exception.
75
   * @param s possibly null additional detail about the exception.
76
   * @param x a possibly null root exception that caused this one.
76
   * @param x a possibly null root exception that caused this one.
77
   */
77
   */
(-)IAuthInfoProvider.java (-30 / +29 lines)
Lines 47-117 Link Here
47
 */
47
 */
48
public interface IAuthInfoProvider
48
public interface IAuthInfoProvider
49
{
49
{
50
51
  // Constants
52
  // -------------------------------------------------------------------------
53
54
  // Methods
55
  // -------------------------------------------------------------------------
56
57
  /**
50
  /**
58
   * Activates (initialises) this provider instance. SHOULD be the first method
51
   * Activates (initialises) this provider instance. SHOULD be the first method
59
   * invoked on the provider.
52
   * invoked on the provider.
60
   *
53
   * 
61
   * @param context a collection of name-value bindings describing the
54
   * @param context a collection of name-value bindings describing the
62
   * activation context.
55
   *          activation context.
63
   * @throws AuthenticationException if an exception occurs during the operation.
56
   * @throws AuthenticationException if an exception occurs during the
57
   *           operation.
64
   */
58
   */
65
  void activate(Map context) throws AuthenticationException;
59
  void activate(Map context) throws AuthenticationException;
66
60
67
  /**
61
  /**
68
   * Passivates (releases) this provider instance. SHOULD be the last method
62
   * Passivates (releases) this provider instance. SHOULD be the last method
69
   * invoked on the provider. Once it is done, no other method may be invoked
63
   * invoked on the provider. Once it is done, no other method may be invoked on
70
   * on the same instance before it is <i>activated</i> agains.
64
   * the same instance before it is <i>activated</i> agains.
71
   *
65
   * 
72
   * @throws AuthenticationException if an exception occurs during the operation.
66
   * @throws AuthenticationException if an exception occurs during the
67
   *           operation.
73
   */
68
   */
74
  void passivate() throws AuthenticationException;
69
  void passivate() throws AuthenticationException;
75
70
76
  /**
71
  /**
77
   * Checks if a user with a designated name is known to this provider.
72
   * Checks if a user with a designated name is known to this provider.
78
   *
73
   * 
79
   * @param userName the name of a user to check.
74
   * @param userName the name of a user to check.
80
   * @return <code>true</code> if the user with the designated name is known to
75
   * @return <code>true</code> if the user with the designated name is known
81
   * this provider; <code>false</code> otherwise.
76
   *         to this provider; <code>false</code> otherwise.
82
   * @throws AuthenticationException if an exception occurs during the operation.
77
   * @throws AuthenticationException if an exception occurs during the
78
   *           operation.
83
   */
79
   */
84
  boolean contains(String userName) throws AuthenticationException;
80
  boolean contains(String userName) throws AuthenticationException;
85
81
86
  /**
82
  /**
87
   * Returns a collection of information about a designated user. The contents
83
   * Returns a collection of information about a designated user. The contents
88
   * of the returned map is provider-specific of name-to-value mappings.
84
   * of the returned map is provider-specific of name-to-value mappings.
89
   *
85
   * 
90
   * @param userID a map of name-to-value bindings that fully describe a user.
86
   * @param userID a map of name-to-value bindings that fully describe a user.
91
   * @return a collection of information about the designated user.
87
   * @return a collection of information about the designated user.
92
   * @throws AuthenticationException if an exception occurs during the operation.
88
   * @throws AuthenticationException if an exception occurs during the
89
   *           operation.
93
   */
90
   */
94
  Map lookup(Map userID) throws AuthenticationException;
91
  Map lookup(Map userID) throws AuthenticationException;
95
92
96
  /**
93
  /**
97
   * Updates the credentials of a designated user.
94
   * Updates the credentials of a designated user.
98
   *
95
   * 
99
   * @param userCredentials a map of name-to-value bindings that fully describe
96
   * @param userCredentials a map of name-to-value bindings that fully describe
100
   * a user, including per new credentials.
97
   *          a user, including per new credentials.
101
   * @throws AuthenticationException if an exception occurs during the operation.
98
   * @throws AuthenticationException if an exception occurs during the
99
   *           operation.
102
   */
100
   */
103
  void update(Map userCredentials) throws AuthenticationException;
101
  void update(Map userCredentials) throws AuthenticationException;
104
102
105
  /**
103
  /**
106
   * A provider may operate in more than mode; e.g. SRP-II caters for user
104
   * A provider may operate in more than mode; e.g. SRP-II caters for user
107
   * credentials computed in more than one message digest algorithm. This
105
   * credentials computed in more than one message digest algorithm. This method
108
   * method returns the set of name-to-value bindings describing the mode of
106
   * returns the set of name-to-value bindings describing the mode of the
109
   * the provider.
107
   * provider.
110
   *
108
   * 
111
   * @param mode a unique identifier describing the operational mode.
109
   * @param mode a unique identifier describing the operational mode.
112
   * @return a collection of name-to-value bindings describing the designated
110
   * @return a collection of name-to-value bindings describing the designated
113
   * mode.
111
   *         mode.
114
   * @throws AuthenticationException if an exception occurs during the operation.
112
   * @throws AuthenticationException if an exception occurs during the
113
   *           operation.
115
   */
114
   */
116
  Map getConfiguration(String mode) throws AuthenticationException;
115
  Map getConfiguration(String mode) throws AuthenticationException;
117
}
116
}
(-)IAuthInfoProviderFactory.java (-12 / +5 lines)
Lines 43-62 Link Here
43
 */
43
 */
44
public interface IAuthInfoProviderFactory
44
public interface IAuthInfoProviderFactory
45
{
45
{
46
47
  // Constants
48
  // -------------------------------------------------------------------------
49
50
  // Methods
51
  // -------------------------------------------------------------------------
52
53
  /**
46
  /**
54
   * Returns an implementation of a provider for a designated mechanism
47
   * Returns an implementation of a provider for a designated mechanism capable
55
   * capable of honouring {@link IAuthInfoProvider} requests.
48
   * of honouring {@link IAuthInfoProvider} requests.
56
   *
49
   * 
57
   * @param mechanism the unique name of a mechanism.
50
   * @param mechanism the unique name of a mechanism.
58
   * @return an implementation of {@link IAuthInfoProvider} for that mechanism
51
   * @return an implementation of {@link IAuthInfoProvider} for that mechanism
59
   * or <code>null</code> if none found.
52
   *         or <code>null</code> if none found.
60
   */
53
   */
61
  IAuthInfoProvider getInstance(String mechanism);
54
  IAuthInfoProvider getInstance(String mechanism);
62
}
55
}
(-)IllegalMechanismStateException.java (-4 / +4 lines)
Lines 47-55 Link Here
47
 * invoked on incomplete mechanisms was invoked but the authentication phase of
47
 * invoked on incomplete mechanisms was invoked but the authentication phase of
48
 * that mechanism was already completed.
48
 * that mechanism was already completed.
49
 */
49
 */
50
public class IllegalMechanismStateException extends AuthenticationException
50
public class IllegalMechanismStateException
51
    extends AuthenticationException
51
{
52
{
52
53
  /**
53
  /**
54
   * Constructs a new instance of <code>IllegalMechanismStateException</code>
54
   * Constructs a new instance of <code>IllegalMechanismStateException</code>
55
   * with no detail message.
55
   * with no detail message.
Lines 62-68 Link Here
62
  /**
62
  /**
63
   * Constructs a new instance of <code>IllegalMechanismStateException</code>
63
   * Constructs a new instance of <code>IllegalMechanismStateException</code>
64
   * with the specified detail message.
64
   * with the specified detail message.
65
   *
65
   * 
66
   * @param detail the detail message.
66
   * @param detail the detail message.
67
   */
67
   */
68
  public IllegalMechanismStateException(String detail)
68
  public IllegalMechanismStateException(String detail)
Lines 73-79 Link Here
73
  /**
73
  /**
74
   * Constructs a new instance of <code>IllegalMechanismStateException</code>
74
   * Constructs a new instance of <code>IllegalMechanismStateException</code>
75
   * with the specified detail message, and cause.
75
   * with the specified detail message, and cause.
76
   *
76
   * 
77
   * @param detail the detail message.
77
   * @param detail the detail message.
78
   * @param ex the original cause.
78
   * @param ex the original cause.
79
   */
79
   */
(-)InputBuffer.java (-139 / +72 lines)
Lines 45-83 Link Here
45
import java.math.BigInteger;
45
import java.math.BigInteger;
46
46
47
/**
47
/**
48
 * <p>The implementation of an incoming SASL buffer.</p>
48
 * The implementation of an incoming SASL buffer.
49
 *
49
 * <p>
50
 * <p>The data elements this class caters for are described in [1].</p>
50
 * The data elements this class caters for are described in [1].
51
 *
51
 * <p>
52
 * <p>References:</p>
52
 * References:
53
 * <ol>
53
 * <ol>
54
 *    <li><a href="http://www.ietf.org/internet-drafts/draft-burdis-cat-srp-sasl-09.txt">
54
 * <li><a
55
 *    Secure Remote Password Authentication Mechanism</a>;<br/>
55
 * href="http://www.ietf.org/internet-drafts/draft-burdis-cat-srp-sasl-09.txt">
56
 *    draft-burdis-cat-srp-sasl-09,<br/>
56
 * Secure Remote Password Authentication Mechanism</a>;<br/>
57
 *    <a href="mailto:keith@rucus.ru.ac.za">Keith Burdis</a> and
57
 * draft-burdis-cat-srp-sasl-09,<br/> <a
58
 *    <a href="mailto:raif@forge.com.au">Ra&iuml;f S. Naffah</a>.</li>
58
 * href="mailto:keith@rucus.ru.ac.za">Keith Burdis</a> and <a
59
 * href="mailto:raif@forge.com.au">Ra&iuml;f S. Naffah</a>.</li>
59
 * </ol>
60
 * </ol>
60
 */
61
 */
61
public class InputBuffer
62
public class InputBuffer
62
{
63
{
63
64
  // Constants and variables
65
  // -------------------------------------------------------------------------
66
67
  /** The internal buffer stream containing the buffer's contents. */
64
  /** The internal buffer stream containing the buffer's contents. */
68
  protected ByteArrayInputStream in;
65
  protected ByteArrayInputStream in;
69
70
  /** The length of the buffer, according to its header. */
66
  /** The length of the buffer, according to its header. */
71
  protected int length;
67
  protected int length;
72
68
73
  // Constructor(s)
74
  // -------------------------------------------------------------------------
75
76
  /**
69
  /**
77
   * <p>Constructs a SASL buffer given the buffer's encoded form, including its
70
   * Constructs a SASL buffer given the buffer's encoded form, including its
78
   * header bytes.</p>
71
   * header bytes.
79
   *
72
   * 
80
   * @param frame the encoded form, including the header bytes, of a SASL buffer.
73
   * @param frame the encoded form, including the header bytes, of a SASL
74
   *          buffer.
81
   * @throws SaslEncodingException if the buffer is malformed.
75
   * @throws SaslEncodingException if the buffer is malformed.
82
   */
76
   */
83
  public InputBuffer(byte[] frame) throws SaslEncodingException
77
  public InputBuffer(byte[] frame) throws SaslEncodingException
Lines 85-101 Link Here
85
    this();
79
    this();
86
80
87
    if (frame.length < 4)
81
    if (frame.length < 4)
88
      {
82
      throw new SaslEncodingException("SASL buffer header too short");
89
        throw new SaslEncodingException("SASL buffer header too short");
83
    length = (frame[0] & 0xFF) << 24
90
      }
84
           | (frame[1] & 0xFF) << 16
91
85
           | (frame[2] & 0xFF) << 8
92
    length = (frame[0] & 0xFF) << 24 | (frame[1] & 0xFF) << 16
86
           | (frame[3] & 0xFF);
93
             | (frame[2] & 0xFF) << 8 | (frame[3] & 0xFF);
94
    if (length > Registry.SASL_BUFFER_MAX_LIMIT || length < 0)
87
    if (length > Registry.SASL_BUFFER_MAX_LIMIT || length < 0)
95
      {
88
      throw new SaslEncodingException("SASL buffer size limit exceeded");
96
        throw new SaslEncodingException("SASL buffer size limit exceeded");
97
      }
98
99
    in = new ByteArrayInputStream(frame, 4, length);
89
    in = new ByteArrayInputStream(frame, 4, length);
100
  }
90
  }
101
91
Lines 105-120 Link Here
105
    super();
95
    super();
106
  }
96
  }
107
97
108
  // Class methods
109
  // -------------------------------------------------------------------------
110
111
  /**
98
  /**
112
   * <p>Returns an instance of a SASL buffer given the buffer's encoded contents,
99
   * Returns an instance of a SASL buffer given the buffer's encoded contents,
113
   * excluding the buffer's header bytes.</p>
100
   * excluding the buffer's header bytes.
114
   *
101
   * <p>
115
   * <p>Calls the method with the same name and three arguments as:
102
   * Calls the method with the same name and three arguments as:
116
   * <code>getInstance(raw, 0, raw.length)</code>.
103
   * <code>getInstance(raw, 0, raw.length)</code>.
117
   *
104
   * 
118
   * @param raw the encoded form, excluding the header bytes, of a SASL buffer.
105
   * @param raw the encoded form, excluding the header bytes, of a SASL buffer.
119
   * @return a new instance of {@link InputBuffer}.
106
   * @return a new instance of {@link InputBuffer}.
120
   */
107
   */
Lines 124-132 Link Here
124
  }
111
  }
125
112
126
  /**
113
  /**
127
   * <p>Returns an instance of a SASL buffer given the buffer's encoded
114
   * Returns an instance of a SASL buffer given the buffer's encoded contents,
128
   * contents, excluding the buffer's header bytes.</p>
115
   * excluding the buffer's header bytes.
129
   *
116
   * 
130
   * @param raw the encoded form, excluding the header bytes, of a SASL buffer.
117
   * @param raw the encoded form, excluding the header bytes, of a SASL buffer.
131
   * @param offset offset where to start using raw bytes from.
118
   * @param offset offset where to start using raw bytes from.
132
   * @param len number of bytes to use.
119
   * @param len number of bytes to use.
Lines 140-160 Link Here
140
  }
127
  }
141
128
142
  /**
129
  /**
143
   * <p>Converts four octets into the number that they represent.</p>
130
   * Converts two octets into the number that they represent.
144
   *
131
   * 
145
   * @param b the four octets.
146
   * @return the length.
147
   */
148
  //   public static int fourBytesToLength(byte[] b) throws SaslEncodingException {
149
  //      int result = b[0] << 24 | (b[1] & 0xFF) << 16 | (b[2] & 0xFF) << 8 | (b[3] & 0xFF);
150
  //      if (result > Registry.SASL_FOUR_BYTE_MAX_LIMIT || result < 0) {
151
  //         throw new SaslEncodingException("SASL EOS size limit exceeded");
152
  //      }
153
  //      return result;
154
  //   }
155
  /**
156
   * <p>Converts two octets into the number that they represent.</p>
157
   *
158
   * @param b the two octets.
132
   * @param b the two octets.
159
   * @return the length.
133
   * @return the length.
160
   */
134
   */
Lines 162-210 Link Here
162
  {
136
  {
163
    final int result = (b[0] & 0xFF) << 8 | (b[1] & 0xFF);
137
    final int result = (b[0] & 0xFF) << 8 | (b[1] & 0xFF);
164
    if (result > Registry.SASL_TWO_BYTE_MAX_LIMIT)
138
    if (result > Registry.SASL_TWO_BYTE_MAX_LIMIT)
165
      {
139
      throw new SaslEncodingException("SASL MPI/Text size limit exceeded");
166
        throw new SaslEncodingException("SASL MPI/Text size limit exceeded");
167
      }
168
    return result;
140
    return result;
169
  }
141
  }
170
142
171
  // Instance methods
172
  // -------------------------------------------------------------------------
173
174
  public boolean hasMoreElements()
143
  public boolean hasMoreElements()
175
  {
144
  {
176
    return (in.available() > 0);
145
    return (in.available() > 0);
177
  }
146
  }
178
147
179
  /**
148
  /**
180
   * <p>Decodes a SASL scalar quantity, <code>count</code>-octet long, from the
149
   * Decodes a SASL scalar quantity, <code>count</code>-octet long, from the
181
   * current buffer.</p>
150
   * current buffer.
182
   *
151
   * 
183
   * @param count the number of octets of this scalar quantity.
152
   * @param count the number of octets of this scalar quantity.
184
   * @return a native representation of a SASL scalar (unsigned integer) quantity.
153
   * @return a native representation of a SASL scalar (unsigned integer)
154
   *         quantity.
185
   * @throws SaslEncodingException if an encoding exception occurs during the
155
   * @throws SaslEncodingException if an encoding exception occurs during the
186
   * operation.
156
   *           operation.
187
   * @throws IOException if any other I/O exception occurs during the operation.
157
   * @throws IOException if any other I/O exception occurs during the operation.
188
   */
158
   */
189
  public long getScalar(int count) throws IOException
159
  public long getScalar(int count) throws IOException
190
  {
160
  {
191
    if (count < 0 || count > 4)
161
    if (count < 0 || count > 4)
192
      {
162
      throw new SaslEncodingException("Invalid SASL scalar octet count: "
193
        throw new SaslEncodingException("Invalid SASL scalar octet count: "
163
                                      + String.valueOf(count));
194
                                        + String.valueOf(count));
164
    if (! hasMoreElements())
195
      }
165
      throw new SaslEncodingException("Not enough bytes for a scalar in buffer");
196
    if (!hasMoreElements())
197
      {
198
        throw new SaslEncodingException(
199
                                        "Not enough bytes for a scalar in buffer");
200
      }
201
    if (in.available() < count)
166
    if (in.available() < count)
202
      {
167
      throw new SaslEncodingException("Illegal SASL scalar encoding");
203
        throw new SaslEncodingException("Illegal SASL scalar encoding");
204
      }
205
    byte[] element = new byte[count];
168
    byte[] element = new byte[count];
206
    in.read(element);
169
    in.read(element);
207
208
    long result = 0L;
170
    long result = 0L;
209
    for (int i = 0; i < count; i++)
171
    for (int i = 0; i < count; i++)
210
      {
172
      {
Lines 215-339 Link Here
215
  }
177
  }
216
178
217
  /**
179
  /**
218
   * <p>Decodes a SASL OS from the current buffer.</p>
180
   * Decodes a SASL OS from the current buffer.
219
   *
181
   * 
220
   * @return a native representation of a SASL OS.
182
   * @return a native representation of a SASL OS.
221
   * @throws SaslEncodingException if an encoding exception occurs during the
183
   * @throws SaslEncodingException if an encoding exception occurs during the
222
   * operation.
184
   *           operation.
223
   * @throws IOException if any other I/O exception occurs during the operation.
185
   * @throws IOException if any other I/O exception occurs during the operation.
224
   */
186
   */
225
  public byte[] getOS() throws IOException
187
  public byte[] getOS() throws IOException
226
  {
188
  {
227
    if (!hasMoreElements())
189
    if (! hasMoreElements())
228
      {
190
      throw new SaslEncodingException(
229
        throw new SaslEncodingException(
191
          "Not enough bytes for an octet-sequence in buffer");
230
                                        "Not enough bytes for an octet-sequence in buffer");
231
      }
232
    final int elementLength = in.read();
192
    final int elementLength = in.read();
233
    if (elementLength > Registry.SASL_ONE_BYTE_MAX_LIMIT)
193
    if (elementLength > Registry.SASL_ONE_BYTE_MAX_LIMIT)
234
      {
194
      throw new SaslEncodingException("SASL octet-sequence size limit exceeded");
235
        throw new SaslEncodingException(
236
                                        "SASL octet-sequence size limit exceeded");
237
      }
238
239
    if (in.available() < elementLength)
195
    if (in.available() < elementLength)
240
      {
196
      throw new SaslEncodingException("Illegal SASL octet-sequence encoding");
241
        throw new SaslEncodingException("Illegal SASL octet-sequence encoding");
242
      }
243
244
    byte[] result = new byte[elementLength];
197
    byte[] result = new byte[elementLength];
245
    in.read(result);
198
    in.read(result);
246
247
    return result;
199
    return result;
248
  }
200
  }
249
201
250
  /**
202
  /**
251
   * <p>Decodes a SASL EOS from the current buffer.</p>
203
   * Decodes a SASL EOS from the current buffer.
252
   *
204
   * 
253
   * @return a native representation of a SASL EOS.
205
   * @return a native representation of a SASL EOS.
254
   * @throws SaslEncodingException if an encoding exception occurs during the
206
   * @throws SaslEncodingException if an encoding exception occurs during the
255
   * operation.
207
   *           operation.
256
   * @throws IOException if any other I/O exception occurs during the operation.
208
   * @throws IOException if any other I/O exception occurs during the operation.
257
   */
209
   */
258
  public byte[] getEOS() throws IOException
210
  public byte[] getEOS() throws IOException
259
  {
211
  {
260
    if (in.available() < 2)
212
    if (in.available() < 2)
261
      {
213
      throw new SaslEncodingException(
262
        throw new SaslEncodingException(
214
          "Not enough bytes for an extended octet-sequence in buffer");
263
                                        "Not enough bytes for an extended octet-sequence in buffer");
264
      }
265
266
    byte[] elementLengthBytes = new byte[2];
215
    byte[] elementLengthBytes = new byte[2];
267
    in.read(elementLengthBytes);
216
    in.read(elementLengthBytes);
268
    final int elementLength = twoBytesToLength(elementLengthBytes);
217
    final int elementLength = twoBytesToLength(elementLengthBytes);
269
    if (in.available() < elementLength)
218
    if (in.available() < elementLength)
270
      {
219
      throw new SaslEncodingException(
271
        throw new SaslEncodingException(
220
          "Illegal SASL extended octet-sequence encoding");
272
                                        "Illegal SASL extended octet-sequence encoding");
273
      }
274
275
    byte[] result = new byte[elementLength];
221
    byte[] result = new byte[elementLength];
276
    in.read(result);
222
    in.read(result);
277
278
    return result;
223
    return result;
279
  }
224
  }
280
225
281
  /**
226
  /**
282
   * <p>Decodes a SASL MPI from the current buffer.</p>
227
   * Decodes a SASL MPI from the current buffer.
283
   *
228
   * 
284
   * @return a native representation of a SASL MPI.
229
   * @return a native representation of a SASL MPI.
285
   * @throws SaslEncodingException if an encoding exception occurs during the
230
   * @throws SaslEncodingException if an encoding exception occurs during the
286
   * operation.
231
   *           operation.
287
   * @throws IOException if any other I/O exception occurs during the operation.
232
   * @throws IOException if any other I/O exception occurs during the operation.
288
   */
233
   */
289
  public BigInteger getMPI() throws IOException
234
  public BigInteger getMPI() throws IOException
290
  {
235
  {
291
    if (in.available() < 2)
236
    if (in.available() < 2)
292
      {
237
      throw new SaslEncodingException("Not enough bytes for an MPI in buffer");
293
        throw new SaslEncodingException("Not enough bytes for an MPI in buffer");
294
      }
295
    byte[] elementLengthBytes = new byte[2];
238
    byte[] elementLengthBytes = new byte[2];
296
    in.read(elementLengthBytes);
239
    in.read(elementLengthBytes);
297
    final int elementLength = twoBytesToLength(elementLengthBytes);
240
    final int elementLength = twoBytesToLength(elementLengthBytes);
298
    if (in.available() < elementLength)
241
    if (in.available() < elementLength)
299
      {
242
      throw new SaslEncodingException(
300
        throw new SaslEncodingException(
243
          "Illegal SASL multi-precision integer encoding");
301
                                        "Illegal SASL multi-precision integer encoding");
302
      }
303
304
    byte[] element = new byte[elementLength];
244
    byte[] element = new byte[elementLength];
305
    in.read(element);
245
    in.read(element);
306
307
    return new BigInteger(1, element);
246
    return new BigInteger(1, element);
308
  }
247
  }
309
248
310
  /**
249
  /**
311
   * <p>Decodes a SASL Text from the current buffer.</p>
250
   * Decodes a SASL Text from the current buffer.
312
   *
251
   * 
313
   * @return a native representation of a SASL Text.
252
   * @return a native representation of a SASL Text.
314
   * @throws SaslEncodingException if an encoding exception occurs during the
253
   * @throws SaslEncodingException if an encoding exception occurs during the
315
   * operation.
254
   *           operation.
316
   * @throws SaslEncodingException if the UTF-8 character encoding is not
255
   * @throws SaslEncodingException if the UTF-8 character encoding is not
317
   * supported on this platform.
256
   *           supported on this platform.
318
   * @throws IOException if any other I/O exception occurs during the operation.
257
   * @throws IOException if any other I/O exception occurs during the operation.
319
   */
258
   */
320
  public String getText() throws IOException
259
  public String getText() throws IOException
321
  {
260
  {
322
    if (in.available() < 2)
261
    if (in.available() < 2)
323
      {
262
      throw new SaslEncodingException("Not enough bytes for a text in buffer");
324
        throw new SaslEncodingException("Not enough bytes for a text in buffer");
325
      }
326
    byte[] elementLengthBytes = new byte[2];
263
    byte[] elementLengthBytes = new byte[2];
327
    in.read(elementLengthBytes);
264
    in.read(elementLengthBytes);
328
    final int elementLength = twoBytesToLength(elementLengthBytes);
265
    final int elementLength = twoBytesToLength(elementLengthBytes);
329
    if (in.available() < elementLength)
266
    if (in.available() < elementLength)
330
      {
267
      throw new SaslEncodingException("Illegal SASL text encoding");
331
        throw new SaslEncodingException("Illegal SASL text encoding");
332
      }
333
334
    byte[] element = new byte[elementLength];
268
    byte[] element = new byte[elementLength];
335
    in.read(element);
269
    in.read(element);
336
337
    return new String(element, "UTF8");
270
    return new String(element, "UTF8");
338
  }
271
  }
339
}
272
}
(-)IntegrityException.java (-5 / +5 lines)
Lines 46-54 Link Here
46
 * processing of an <i>integrity</i> protection filter, including <i>replay
46
 * processing of an <i>integrity</i> protection filter, including <i>replay
47
 * detection</i>.
47
 * detection</i>.
48
 */
48
 */
49
public class IntegrityException extends SaslException
49
public class IntegrityException
50
    extends SaslException
50
{
51
{
51
52
  /**
52
  /**
53
   * Constructs a new instance of <code>IntegrityException</code> with no
53
   * Constructs a new instance of <code>IntegrityException</code> with no
54
   * detail message.
54
   * detail message.
Lines 61-67 Link Here
61
  /**
61
  /**
62
   * Constructs a new instance of <code>IntegrityException</code> with the
62
   * Constructs a new instance of <code>IntegrityException</code> with the
63
   * specified detail message.
63
   * specified detail message.
64
   *
64
   * 
65
   * @param s the detail message.
65
   * @param s the detail message.
66
   */
66
   */
67
  public IntegrityException(String s)
67
  public IntegrityException(String s)
Lines 72-78 Link Here
72
  /**
72
  /**
73
   * Constructs a new instance of <code>IntegrityException</code> with a
73
   * Constructs a new instance of <code>IntegrityException</code> with a
74
   * detailed message and a root exception.
74
   * detailed message and a root exception.
75
   *
75
   * 
76
   * @param s possibly null additional detail about the exception.
76
   * @param s possibly null additional detail about the exception.
77
   * @param x a possibly null root exception that caused this one.
77
   * @param x a possibly null root exception that caused this one.
78
   */
78
   */
Lines 80-83 Link Here
80
  {
80
  {
81
    super(s, x);
81
    super(s, x);
82
  }
82
  }
83
}
83
}
(-)NoSuchMechanismException.java (-5 / +5 lines)
Lines 44-62 Link Here
44
 * A checked exception thrown to indicate that a designated SASL mechanism
44
 * A checked exception thrown to indicate that a designated SASL mechanism
45
 * implementation was not found.
45
 * implementation was not found.
46
 */
46
 */
47
public class NoSuchMechanismException extends SaslException
47
public class NoSuchMechanismException
48
    extends SaslException
48
{
49
{
49
50
  /**
50
  /**
51
   * Constructs a <code>NoSuchMechanismException</code> with the specified
51
   * Constructs a <code>NoSuchMechanismException</code> with the specified
52
   * detail message. In the case of this exception, the detail message
52
   * detail message. In the case of this exception, the detail message
53
   * designates the offending mechanism name.
53
   * designates the offending mechanism name.
54
   *
54
   * 
55
   * @param arg the detail message, which in this case is the offending
55
   * @param arg the detail message, which in this case is the offending
56
   * mechanism name.
56
   *          mechanism name.
57
   */
57
   */
58
  public NoSuchMechanismException(String arg)
58
  public NoSuchMechanismException(String arg)
59
  {
59
  {
60
    super(arg);
60
    super(arg);
61
  }
61
  }
62
}
62
}
(-)NoSuchUserException.java (-5 / +5 lines)
Lines 44-52 Link Here
44
 * A checked exception thrown to indicate that a designated user is unknown to
44
 * A checked exception thrown to indicate that a designated user is unknown to
45
 * the authentication layer.
45
 * the authentication layer.
46
 */
46
 */
47
public class NoSuchUserException extends AuthenticationException
47
public class NoSuchUserException
48
    extends AuthenticationException
48
{
49
{
49
50
  /** Constructs a <code>NoSuchUserException</code> with no detail message. */
50
  /** Constructs a <code>NoSuchUserException</code> with no detail message. */
51
  public NoSuchUserException()
51
  public NoSuchUserException()
52
  {
52
  {
Lines 55-63 Link Here
55
55
56
  /**
56
  /**
57
   * Constructs a <code>NoSuchUserException</code> with the specified detail
57
   * Constructs a <code>NoSuchUserException</code> with the specified detail
58
   * message. In the case of this exception, the detail message designates
58
   * message. In the case of this exception, the detail message designates the
59
   * the offending username.
59
   * offending username.
60
   *
60
   * 
61
   * @param arg the detail message, which in this case is the username.
61
   * @param arg the detail message, which in this case is the username.
62
   */
62
   */
63
  public NoSuchUserException(String arg)
63
  public NoSuchUserException(String arg)
(-)OutputBuffer.java (-70 / +43 lines)
Lines 46-76 Link Here
46
import java.math.BigInteger;
46
import java.math.BigInteger;
47
47
48
/**
48
/**
49
 * <p>The implementation of an outgoing SASL buffer.</p>
49
 * The implementation of an outgoing SASL buffer.
50
 *
50
 * <p>
51
 * <p>The data elements this class caters for are described in [1].</p>
51
 * The data elements this class caters for are described in [1].
52
 *
52
 * <p>
53
 * <p>References:</p>
53
 * References:
54
 * <ol>
54
 * <ol>
55
 *    <li><a href="http://www.ietf.org/internet-drafts/draft-burdis-cat-srp-sasl-09.txt">
55
 * <li><a
56
 *    Secure Remote Password Authentication Mechanism</a>;<br/>
56
 * href="http://www.ietf.org/internet-drafts/draft-burdis-cat-srp-sasl-09.txt">
57
 *    draft-burdis-cat-srp-sasl-09,<br/>
57
 * Secure Remote Password Authentication Mechanism</a>;<br/>
58
 *    <a href="mailto:keith@rucus.ru.ac.za">Keith Burdis</a> and
58
 * draft-burdis-cat-srp-sasl-09,<br/> <a
59
 *    <a href="mailto:raif@forge.com.au">Ra&iuml;f S. Naffah</a>.</li>
59
 * href="mailto:keith@rucus.ru.ac.za">Keith Burdis</a> and <a
60
 * href="mailto:raif@forge.com.au">Ra&iuml;f S. Naffah</a>.</li>
60
 * </ol>
61
 * </ol>
61
 */
62
 */
62
public class OutputBuffer
63
public class OutputBuffer
63
{
64
{
64
65
  // Constants and variables
66
  // -------------------------------------------------------------------------
67
68
  /** The internal output stream. */
65
  /** The internal output stream. */
69
  private ByteArrayOutputStream out;
66
  private ByteArrayOutputStream out;
70
67
71
  // Constructor(s)
72
  // -------------------------------------------------------------------------
73
74
  public OutputBuffer()
68
  public OutputBuffer()
75
  {
69
  {
76
    super();
70
    super();
Lines 78-93 Link Here
78
    out = new ByteArrayOutputStream();
72
    out = new ByteArrayOutputStream();
79
  }
73
  }
80
74
81
  // Class methods
82
  // -------------------------------------------------------------------------
83
84
  // Instance methods
85
  // -------------------------------------------------------------------------
86
87
  /**
75
  /**
88
   * <p>Encodes a SASL scalar quantity, <code>count</code>-octet long, to the
76
   * Encodes a SASL scalar quantity, <code>count</code>-octet long, to the
89
   * current buffer.</p>
77
   * current buffer.
90
   *
78
   * 
91
   * @param count number of octets to encode <code>b</code> with.
79
   * @param count number of octets to encode <code>b</code> with.
92
   * @param b the scalar quantity.
80
   * @param b the scalar quantity.
93
   * @throws SaslEncodingException if an encoding size constraint is violated.
81
   * @throws SaslEncodingException if an encoding size constraint is violated.
Lines 96-116 Link Here
96
  public void setScalar(int count, int b) throws IOException
84
  public void setScalar(int count, int b) throws IOException
97
  {
85
  {
98
    if (count < 0 || count > 4)
86
    if (count < 0 || count > 4)
99
      {
87
      throw new SaslEncodingException("Invalid SASL scalar octet count: "
100
        throw new SaslEncodingException("Invalid SASL scalar octet count: "
88
                                      + String.valueOf(count));
101
                                        + String.valueOf(count));
102
      }
103
    byte[] element = new byte[count];
89
    byte[] element = new byte[count];
104
    for (int i = count; --i >= 0; b >>>= 8)
90
    for (int i = count; --i >= 0; b >>>= 8)
105
      {
91
      element[i] = (byte) b;
106
        element[i] = (byte) b;
107
      }
108
    out.write(element);
92
    out.write(element);
109
  }
93
  }
110
94
111
  /**
95
  /**
112
   * <p>Encodes a SASL OS to the current buffer.</p>
96
   * Encodes a SASL OS to the current buffer.
113
   *
97
   * 
114
   * @param b the OS element.
98
   * @param b the OS element.
115
   * @throws SaslEncodingException if an encoding size constraint is violated.
99
   * @throws SaslEncodingException if an encoding size constraint is violated.
116
   * @throws IOException if any other I/O exception occurs during the operation.
100
   * @throws IOException if any other I/O exception occurs during the operation.
Lines 119-134 Link Here
119
  {
103
  {
120
    final int length = b.length;
104
    final int length = b.length;
121
    if (length > Registry.SASL_ONE_BYTE_MAX_LIMIT)
105
    if (length > Registry.SASL_ONE_BYTE_MAX_LIMIT)
122
      {
106
      throw new SaslEncodingException("SASL octet-sequence too long");
123
        throw new SaslEncodingException("SASL octet-sequence too long");
124
      }
125
    out.write(length & 0xFF);
107
    out.write(length & 0xFF);
126
    out.write(b);
108
    out.write(b);
127
  }
109
  }
128
110
129
  /**
111
  /**
130
   * <p>Encodes a SASL EOS to the current buffer.</p>
112
   * Encodes a SASL EOS to the current buffer.
131
   *
113
   * 
132
   * @param b the EOS element.
114
   * @param b the EOS element.
133
   * @throws SaslEncodingException if an encoding size constraint is violated.
115
   * @throws SaslEncodingException if an encoding size constraint is violated.
134
   * @throws IOException if any other I/O exception occurs during the operation.
116
   * @throws IOException if any other I/O exception occurs during the operation.
Lines 137-153 Link Here
137
  {
119
  {
138
    final int length = b.length;
120
    final int length = b.length;
139
    if (length > Registry.SASL_TWO_BYTE_MAX_LIMIT)
121
    if (length > Registry.SASL_TWO_BYTE_MAX_LIMIT)
140
      {
122
      throw new SaslEncodingException("SASL extended octet-sequence too long");
141
        throw new SaslEncodingException("SASL extended octet-sequence too long");
123
    byte[] lengthBytes = { (byte)(length >>> 8), (byte) length };
142
      }
143
    byte[] lengthBytes = { (byte) (length >>> 8), (byte) length };
144
    out.write(lengthBytes);
124
    out.write(lengthBytes);
145
    out.write(b);
125
    out.write(b);
146
  }
126
  }
147
127
148
  /**
128
  /**
149
   * <p>Encodes a SASL MPI to the current buffer.</p>
129
   * Encodes a SASL MPI to the current buffer.
150
   *
130
   * 
151
   * @param val the MPI element.
131
   * @param val the MPI element.
152
   * @throws SaslEncodingException if an encoding size constraint is violated.
132
   * @throws SaslEncodingException if an encoding size constraint is violated.
153
   * @throws IOException if any other I/O exception occurs during the operation.
133
   * @throws IOException if any other I/O exception occurs during the operation.
Lines 157-177 Link Here
157
    byte[] b = Util.trim(val);
137
    byte[] b = Util.trim(val);
158
    final int length = b.length;
138
    final int length = b.length;
159
    if (length > Registry.SASL_TWO_BYTE_MAX_LIMIT)
139
    if (length > Registry.SASL_TWO_BYTE_MAX_LIMIT)
160
      {
140
      throw new SaslEncodingException("SASL multi-precision integer too long");
161
        throw new SaslEncodingException("SASL multi-precision integer too long");
141
    byte[] lengthBytes = { (byte)(length >>> 8), (byte) length };
162
      }
163
    byte[] lengthBytes = { (byte) (length >>> 8), (byte) length };
164
    out.write(lengthBytes);
142
    out.write(lengthBytes);
165
    out.write(b);
143
    out.write(b);
166
  }
144
  }
167
145
168
  /**
146
  /**
169
   * <p>Encodes a SASL Text to the current buffer.</p>
147
   * Encodes a SASL Text to the current buffer.
170
   *
148
   * 
171
   * @param str the Text element.
149
   * @param str the Text element.
172
   * @throws SaslEncodingException if an encoding size constraint is violated.
150
   * @throws SaslEncodingException if an encoding size constraint is violated.
173
   * @throws SaslEncodingException if the UTF-8 encoding is not supported on
151
   * @throws SaslEncodingException if the UTF-8 encoding is not supported on
174
   * this platform.
152
   *           this platform.
175
   * @throws IOException if any other I/O exception occurs during the operation.
153
   * @throws IOException if any other I/O exception occurs during the operation.
176
   */
154
   */
177
  public void setText(String str) throws IOException
155
  public void setText(String str) throws IOException
Lines 179-196 Link Here
179
    byte[] b = str.getBytes("UTF8");
157
    byte[] b = str.getBytes("UTF8");
180
    final int length = b.length;
158
    final int length = b.length;
181
    if (length > Registry.SASL_TWO_BYTE_MAX_LIMIT)
159
    if (length > Registry.SASL_TWO_BYTE_MAX_LIMIT)
182
      {
160
      throw new SaslEncodingException("SASL text too long");
183
        throw new SaslEncodingException("SASL text too long");
161
    byte[] lengthBytes = { (byte)(length >>> 8), (byte) length };
184
      }
185
    byte[] lengthBytes = { (byte) (length >>> 8), (byte) length };
186
    out.write(lengthBytes);
162
    out.write(lengthBytes);
187
    out.write(b);
163
    out.write(b);
188
  }
164
  }
189
165
190
  /**
166
  /**
191
   * <p>Returns the encoded form of the current buffer including the 4-byte
167
   * Returns the encoded form of the current buffer including the 4-byte length
192
   * length header.</p>
168
   * header.
193
   *
169
   * 
194
   * @throws SaslEncodingException if an encoding size constraint is violated.
170
   * @throws SaslEncodingException if an encoding size constraint is violated.
195
   */
171
   */
196
  public byte[] encode() throws SaslEncodingException
172
  public byte[] encode() throws SaslEncodingException
Lines 198-225 Link Here
198
    byte[] buffer = wrap();
174
    byte[] buffer = wrap();
199
    final int length = buffer.length;
175
    final int length = buffer.length;
200
    byte[] result = new byte[length + 4];
176
    byte[] result = new byte[length + 4];
201
    result[0] = (byte) (length >>> 24);
177
    result[0] = (byte)(length >>> 24);
202
    result[1] = (byte) (length >>> 16);
178
    result[1] = (byte)(length >>> 16);
203
    result[2] = (byte) (length >>> 8);
179
    result[2] = (byte)(length >>> 8);
204
    result[3] = (byte) length;
180
    result[3] = (byte) length;
205
    System.arraycopy(buffer, 0, result, 4, length);
181
    System.arraycopy(buffer, 0, result, 4, length);
206
207
    return result;
182
    return result;
208
  }
183
  }
209
184
210
  /**
185
  /**
211
   * <p>Returns the encoded form of the current buffer excluding the 4-byte
186
   * Returns the encoded form of the current buffer excluding the 4-byte length
212
   * length header.</p>
187
   * header.
213
   *
188
   * 
214
   * @throws SaslEncodingException if an encoding size constraint is violated.
189
   * @throws SaslEncodingException if an encoding size constraint is violated.
215
   */
190
   */
216
  public byte[] wrap() throws SaslEncodingException
191
  public byte[] wrap() throws SaslEncodingException
217
  {
192
  {
218
    final int length = out.size();
193
    final int length = out.size();
219
    if (length > Registry.SASL_BUFFER_MAX_LIMIT || length < 0)
194
    if (length > Registry.SASL_BUFFER_MAX_LIMIT || length < 0)
220
      {
195
      throw new SaslEncodingException("SASL buffer too long");
221
        throw new SaslEncodingException("SASL buffer too long");
222
      }
223
    return out.toByteArray();
196
    return out.toByteArray();
224
  }
197
  }
225
}
198
}
(-)SaslEncodingException.java (-4 / +4 lines)
Lines 44-52 Link Here
44
 * A checked exception, thrown when an exception occurs while decoding a SASL
44
 * A checked exception, thrown when an exception occurs while decoding a SASL
45
 * buffer and/or a SASL data element from/to a buffer.
45
 * buffer and/or a SASL data element from/to a buffer.
46
 */
46
 */
47
public class SaslEncodingException extends SaslException
47
public class SaslEncodingException
48
    extends SaslException
48
{
49
{
49
50
  /** Constructs a <code>SaslEncodingException</code> with no detail message. */
50
  /** Constructs a <code>SaslEncodingException</code> with no detail message. */
51
  public SaslEncodingException()
51
  public SaslEncodingException()
52
  {
52
  {
Lines 56-66 Link Here
56
  /**
56
  /**
57
   * Constructs a <code>SaslEncodingException</code> with the specified detail
57
   * Constructs a <code>SaslEncodingException</code> with the specified detail
58
   * message.
58
   * message.
59
   *
59
   * 
60
   * @param s the detail message.
60
   * @param s the detail message.
61
   */
61
   */
62
  public SaslEncodingException(String s)
62
  public SaslEncodingException(String s)
63
  {
63
  {
64
    super(s);
64
    super(s);
65
  }
65
  }
66
}
66
}
(-)SaslInputStream.java (-86 / +68 lines)
Lines 54-60 Link Here
54
 * An input stream that uses either a {@link SaslClient} or a {@link SaslServer}
54
 * An input stream that uses either a {@link SaslClient} or a {@link SaslServer}
55
 * to process the data through these entities' security layer filter(s).
55
 * to process the data through these entities' security layer filter(s).
56
 */
56
 */
57
public class SaslInputStream extends InputStream
57
public class SaslInputStream
58
    extends InputStream
58
{
59
{
59
  private static final Logger log = Logger.getLogger(SaslInputStream.class.getName());
60
  private static final Logger log = Logger.getLogger(SaslInputStream.class.getName());
60
  private SaslClient client;
61
  private SaslClient client;
Lines 63-78 Link Here
63
  private InputStream source;
64
  private InputStream source;
64
  private byte[] internalBuf;
65
  private byte[] internalBuf;
65
66
66
  // Constructor(s)
67
  // -------------------------------------------------------------------------
68
69
  public SaslInputStream(SaslClient client, InputStream source)
67
  public SaslInputStream(SaslClient client, InputStream source)
70
      throws IOException
68
      throws IOException
71
  {
69
  {
72
    super();
70
    super();
73
71
74
    this.client = client;
72
    this.client = client;
75
    maxRawSendSize = Integer.parseInt((String) client.getNegotiatedProperty(Sasl.RAW_SEND_SIZE));
73
    String size = (String) client.getNegotiatedProperty(Sasl.RAW_SEND_SIZE);
74
    maxRawSendSize = Integer.parseInt(size);
76
    server = null;
75
    server = null;
77
    this.source = source;
76
    this.source = source;
78
  }
77
  }
Lines 83-101 Link Here
83
    super();
82
    super();
84
83
85
    this.server = server;
84
    this.server = server;
86
    maxRawSendSize = Integer.parseInt((String) server.getNegotiatedProperty(Sasl.RAW_SEND_SIZE));
85
    String size = (String) server.getNegotiatedProperty(Sasl.RAW_SEND_SIZE);
86
    maxRawSendSize = Integer.parseInt(size);
87
    client = null;
87
    client = null;
88
    this.source = source;
88
    this.source = source;
89
  }
89
  }
90
90
91
  // Class methods
92
  // -------------------------------------------------------------------------
93
94
  // Instance methods
95
  // -------------------------------------------------------------------------
96
97
  // Overloaded java.io.InputStream methods ----------------------------------
98
99
  public int available() throws IOException
91
  public int available() throws IOException
100
  {
92
  {
101
    return (internalBuf == null) ? 0 : internalBuf.length;
93
    return (internalBuf == null) ? 0 : internalBuf.length;
Lines 107-131 Link Here
107
  }
99
  }
108
100
109
  /**
101
  /**
110
   * <p>Reads the next byte of data from the input stream. The value byte is
102
   * Reads the next byte of data from the input stream. The value byte is
111
   * returned as an <code>int</code> in the range <code>0</code> to
103
   * returned as an <code>int</code> in the range <code>0</code> to
112
   * <code>255</code>. If no byte is available because the end of the stream
104
   * <code>255</code>. If no byte is available because the end of the stream
113
   * has been reached, the value <code>-1</code> is returned. This method
105
   * has been reached, the value <code>-1</code> is returned. This method
114
   * blocks until input data is available, the end of the stream is detected,
106
   * blocks until input data is available, the end of the stream is detected, or
115
   * or an exception is thrown.</p>
107
   * an exception is thrown.
116
   *
108
   * <p>
117
   * <p>From a SASL mechanism provider's perspective, if a security layer has
109
   * From a SASL mechanism provider's perspective, if a security layer has been
118
   * been negotiated, the underlying <i>source</i> is expected to contain SASL
110
   * negotiated, the underlying <i>source</i> is expected to contain SASL
119
   * buffers, as defined in RFC 2222. Four octets in network byte order in the
111
   * buffers, as defined in RFC 2222. Four octets in network byte order in the
120
   * front of each buffer identify the length of the buffer. The provider is
112
   * front of each buffer identify the length of the buffer. The provider is
121
   * responsible for performing any integrity checking or other processing on
113
   * responsible for performing any integrity checking or other processing on
122
   * the buffer before returning the data as a stream of octets. For example,
114
   * the buffer before returning the data as a stream of octets. For example,
123
   * the protocol driver's request for a single octet from the stream might;
115
   * the protocol driver's request for a single octet from the stream might;
124
   * i.e. an invocation of this method, may result in an entire SASL buffer
116
   * i.e. an invocation of this method, may result in an entire SASL buffer
125
   * being read and processed before that single octet can be returned.</p>
117
   * being read and processed before that single octet can be returned.
126
   *
118
   * 
127
   * @return the next byte of data, or <code>-1</code> if the end of the stream
119
   * @return the next byte of data, or <code>-1</code> if the end of the
128
   * is reached.
120
   *         stream is reached.
129
   * @throws IOException if an I/O error occurs.
121
   * @throws IOException if an I/O error occurs.
130
   */
122
   */
131
  public int read() throws IOException
123
  public int read() throws IOException
Lines 149-223 Link Here
149
        int check = read(buf);
141
        int check = read(buf);
150
        result = (check > 0) ? (buf[0] & 0xFF) : -1;
142
        result = (check > 0) ? (buf[0] & 0xFF) : -1;
151
      }
143
      }
152
153
    return result;
144
    return result;
154
  }
145
  }
155
146
156
  /**
147
  /**
157
   * <p>Reads up to <code>len</code> bytes of data from the underlying
148
   * Reads up to <code>len</code> bytes of data from the underlying <i>source</i>
158
   * <i>source</i> input stream into an array of bytes. An attempt is made to
149
   * input stream into an array of bytes. An attempt is made to read as many as
159
   * read as many as <code>len</code> bytes, but a smaller number may be read,
150
   * <code>len</code> bytes, but a smaller number may be read, possibly zero.
160
   * possibly zero. The number of bytes actually read is returned as an
151
   * The number of bytes actually read is returned as an integer.
161
   * integer.</p>
152
   * <p>
162
   *
153
   * This method blocks until input data is available, end of file is detected,
163
   * <p>This method blocks until input data is available, end of file is
154
   * or an exception is thrown.
164
   * detected, or an exception is thrown.</p>
155
   * <p>
165
   *
156
   * If <code>b</code> is <code>null</code>, a {@link NullPointerException}
166
   * <p>If <code>b</code> is <code>null</code>, a {@link NullPointerException} is
157
   * is thrown.
167
   * thrown.</p>
158
   * <p>
168
   *
159
   * If <code>off</code> is negative, or <code>len</code> is negative, or
169
   * <p>If <code>off</code> is negative, or <code>len</code> is negative, or
160
   * <code>off+len</code> is greater than the length of the array
170
   * <code>off+len</code> is greater than the length of the array <code>b</code>,
161
   * <code>b</code>, then an {@link IndexOutOfBoundsException} is thrown.
171
   * then an {@link IndexOutOfBoundsException} is thrown.</p>
162
   * <p>
172
   *
163
   * If <code>len</code> is zero, then no bytes are read and <code>0</code>
173
   * <p>If <code>len</code> is zero, then no bytes are read and <code>0</code>
174
   * is returned; otherwise, there is an attempt to read at least one byte. If
164
   * is returned; otherwise, there is an attempt to read at least one byte. If
175
   * no byte is available because the stream is at end of file, the value
165
   * no byte is available because the stream is at end of file, the value
176
   * <code>-1</code> is returned; otherwise, at least one byte is read and
166
   * <code>-1</code> is returned; otherwise, at least one byte is read and
177
   * stored into <code>b</code>.</p>
167
   * stored into <code>b</code>.
178
   *
168
   * <p>
179
   * <p>The first byte read is stored into element <code>b[off]</code>, the
169
   * The first byte read is stored into element <code>b[off]</code>, the next
180
   * next one into <code>b[off+1]</code>, and so on. The number of bytes read
170
   * one into <code>b[off+1]</code>, and so on. The number of bytes read is,
181
   * is, at most, equal to <code>len</code>. Let <code>k</code> be the number
171
   * at most, equal to <code>len</code>. Let <code>k</code> be the number
182
   * of bytes actually read; these bytes will be stored in elements
172
   * of bytes actually read; these bytes will be stored in elements
183
   * <code>b[off]</code> through <code>b[off+k-1]</code>, leaving elements
173
   * <code>b[off]</code> through <code>b[off+k-1]</code>, leaving elements
184
   * <code>b[off+k]</code> through <code>b[off+len-1]</code> unaffected.</p>
174
   * <code>b[off+k]</code> through <code>b[off+len-1]</code> unaffected.
185
   *
175
   * <p>
186
   * <p>In every case, elements <code>b[0]</code> through <code>b[off]</code>
176
   * In every case, elements <code>b[0]</code> through <code>b[off]</code>
187
   * and elements <code>b[off+len]</code> through <code>b[b.length-1]</code>
177
   * and elements <code>b[off+len]</code> through <code>b[b.length-1]</code>
188
   * are unaffected.</p>
178
   * are unaffected.
189
   *
179
   * <p>
190
   * <p>If the first byte cannot be read for any reason other than end of file,
180
   * If the first byte cannot be read for any reason other than end of file,
191
   * then an {@link IOException} is thrown. In particular, an {@link IOException}
181
   * then an {@link IOException} is thrown. In particular, an
192
   * is thrown if the input stream has been closed.</p>
182
   * {@link IOException} is thrown if the input stream has been closed.
193
   *
183
   * <p>
194
   * <p>From the SASL mechanism provider's perspective, if a security layer has
184
   * From the SASL mechanism provider's perspective, if a security layer has
195
   * been negotiated, the underlying <i>source</i> is expected to contain SASL
185
   * been negotiated, the underlying <i>source</i> is expected to contain SASL
196
   * buffers, as defined in RFC 2222. Four octets in network byte order in the
186
   * buffers, as defined in RFC 2222. Four octets in network byte order in the
197
   * front of each buffer identify the length of the buffer. The provider is
187
   * front of each buffer identify the length of the buffer. The provider is
198
   * responsible for performing any integrity checking or other processing on
188
   * responsible for performing any integrity checking or other processing on
199
   * the buffer before returning the data as a stream of octets. The protocol
189
   * the buffer before returning the data as a stream of octets. The protocol
200
   * driver's request for a single octet from the stream might result in an
190
   * driver's request for a single octet from the stream might result in an
201
   * entire SASL buffer being read and processed before that single octet can
191
   * entire SASL buffer being read and processed before that single octet can be
202
   * be returned.</p>
192
   * returned.
203
   *
193
   * 
204
   * @param b the buffer into which the data is read.
194
   * @param b the buffer into which the data is read.
205
   * @param off the start offset in array <code>b</code> at which the data is
195
   * @param off the start offset in array <code>b</code> at which the data is
206
   * wricodeen.
196
   *          wricodeen.
207
   * @param len the maximum number of bytes to read.
197
   * @param len the maximum number of bytes to read.
208
   * @return the total number of bytes read into the buffer, or <code>-1</code>
198
   * @return the total number of bytes read into the buffer, or <code>-1</code>
209
   * if there is no more data because the end of the stream has been reached.
199
   *         if there is no more data because the end of the stream has been
200
   *         reached.
210
   * @throws IOException if an I/O error occurs.
201
   * @throws IOException if an I/O error occurs.
211
   */
202
   */
212
  public int read(byte[] b, int off, int len) throws IOException
203
  public int read(byte[] b, int off, int len) throws IOException
213
  {
204
  {
214
    if (Configuration.DEBUG)
205
    if (Configuration.DEBUG)
215
      log.entering(this.getClass().getName(), "read",
206
      log.entering(this.getClass().getName(), "read", new Object[] {
216
                   new Object[] { b, Integer.valueOf(off), Integer.valueOf(len) });
207
          b, Integer.valueOf(off), Integer.valueOf(len)
208
      });
217
    if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length)
209
    if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length)
218
        || ((off + len) < 0))
210
        || ((off + len) < 0))
219
      throw new IndexOutOfBoundsException("off=" + off
211
      throw new IndexOutOfBoundsException("off=" + off + ", len=" + len
220
                                          + ", len=" + len
221
                                          + ", b.length=" + b.length);
212
                                          + ", b.length=" + b.length);
222
    if (len == 0)
213
    if (len == 0)
223
      {
214
      {
Lines 254-260 Link Here
254
            }
245
            }
255
          return -1;
246
          return -1;
256
        }
247
        }
257
258
    if (len <= internalBuf.length)
248
    if (len <= internalBuf.length)
259
      {
249
      {
260
        result = len;
250
        result = len;
Lines 274-283 Link Here
274
        result = internalBuf.length;
264
        result = internalBuf.length;
275
        System.arraycopy(internalBuf, 0, b, off, result);
265
        System.arraycopy(internalBuf, 0, b, off, result);
276
        internalBuf = null;
266
        internalBuf = null;
277
278
        off += result;
267
        off += result;
279
        len -= result;
268
        len -= result;
280
281
        int remaining; // count of bytes remaining in buffer after an iteration
269
        int remaining; // count of bytes remaining in buffer after an iteration
282
        int delta; // count of bytes moved to b after an iteration
270
        int delta; // count of bytes moved to b after an iteration
283
        int datalen;
271
        int datalen;
Lines 295-303 Link Here
295
                    log.finer("Underlying stream exhausted. Breaking...");
283
                    log.finer("Underlying stream exhausted. Breaking...");
296
                  break;
284
                  break;
297
                }
285
                }
298
299
              datalen = data.length;
286
              datalen = data.length;
300
301
              // copy [part of] the result to b
287
              // copy [part of] the result to b
302
              remaining = (datalen <= len) ? 0 : datalen - len;
288
              remaining = (datalen <= len) ? 0 : datalen - len;
303
              delta = datalen - remaining;
289
              delta = datalen - remaining;
Lines 307-313 Link Here
307
                  internalBuf = new byte[remaining];
293
                  internalBuf = new byte[remaining];
308
                  System.arraycopy(data, delta, internalBuf, 0, remaining);
294
                  System.arraycopy(data, delta, internalBuf, 0, remaining);
309
                }
295
                }
310
311
              // update off, result and len
296
              // update off, result and len
312
              off += delta;
297
              off += delta;
313
              result += delta;
298
              result += delta;
Lines 322-341 Link Here
322
      }
307
      }
323
    if (Configuration.DEBUG)
308
    if (Configuration.DEBUG)
324
      {
309
      {
325
        log.finer("Remaining: " + (internalBuf == null ? 0 : internalBuf.length));
310
        log.finer("Remaining: "
311
                  + (internalBuf == null ? 0 : internalBuf.length));
326
        log.exiting(this.getClass().getName(), "read()", String.valueOf(result));
312
        log.exiting(this.getClass().getName(), "read()", String.valueOf(result));
327
      }
313
      }
328
    return result;
314
    return result;
329
  }
315
  }
330
316
331
  // other nstance methods ---------------------------------------------------
332
333
  /**
317
  /**
334
   * Reads a SASL buffer from the underlying source if at least 4 bytes are
318
   * Reads a SASL buffer from the underlying source if at least 4 bytes are
335
   * available.
319
   * available.
336
   *
320
   * 
337
   * @return the byte[] of decoded buffer contents, or null if the underlying
321
   * @return the byte[] of decoded buffer contents, or null if the underlying
338
   * source was exhausted.
322
   *         source was exhausted.
339
   * @throws IOException if an I/O exception occurs during the operation.
323
   * @throws IOException if an I/O exception occurs during the operation.
340
   */
324
   */
341
  private byte[] readSaslBuffer() throws IOException
325
  private byte[] readSaslBuffer() throws IOException
Lines 360-371 Link Here
360
          log.throwing(this.getClass().getName(), "readSaslBuffer", x);
344
          log.throwing(this.getClass().getName(), "readSaslBuffer", x);
361
        throw x;
345
        throw x;
362
      }
346
      }
363
364
    if (realLength != 4)
347
    if (realLength != 4)
365
      throw new IOException("Was expecting 4 but found " + realLength);
348
      throw new IOException("Was expecting 4 but found " + realLength);
366
    int bufferLength = result[0] << 24 | (result[1] & 0xFF) << 16
349
    int bufferLength =  result[0]         << 24
367
                       | (result[2] & 0xFF) << 8 | (result[3] & 0xFF);
350
                     | (result[1] & 0xFF) << 16
368
351
                     | (result[2] & 0xFF) << 8
352
                     | (result[3] & 0xFF);
369
    if (Configuration.DEBUG)
353
    if (Configuration.DEBUG)
370
      log.finer("SASL buffer size: " + bufferLength);
354
      log.finer("SASL buffer size: " + bufferLength);
371
    if (bufferLength > maxRawSendSize || bufferLength < 0)
355
    if (bufferLength > maxRawSendSize || bufferLength < 0)
Lines 382-391 Link Here
382
          log.throwing(this.getClass().getName(), "readSaslBuffer", x);
366
          log.throwing(this.getClass().getName(), "readSaslBuffer", x);
383
        throw x;
367
        throw x;
384
      }
368
      }
385
386
    if (realLength != bufferLength)
369
    if (realLength != bufferLength)
387
      throw new IOException("Was expecting " + bufferLength
370
      throw new IOException("Was expecting " + bufferLength + " but found "
388
                            + " but found " + realLength);
371
                            + realLength);
389
    if (Configuration.DEBUG)
372
    if (Configuration.DEBUG)
390
      {
373
      {
391
        log.finer("Incoming buffer (before security) (hex): "
374
        log.finer("Incoming buffer (before security) (hex): "
Lines 397-403 Link Here
397
      result = client.unwrap(result, 0, realLength);
380
      result = client.unwrap(result, 0, realLength);
398
    else
381
    else
399
      result = server.unwrap(result, 0, realLength);
382
      result = server.unwrap(result, 0, realLength);
400
401
    if (Configuration.DEBUG)
383
    if (Configuration.DEBUG)
402
      {
384
      {
403
        log.finer("Incoming buffer (after security) (hex): "
385
        log.finer("Incoming buffer (after security) (hex): "
Lines 408-411 Link Here
408
      }
390
      }
409
    return result;
391
    return result;
410
  }
392
  }
411
}
393
}
(-)SaslOutputStream.java (-20 / +11 lines)
Lines 53-59 Link Here
53
 * An output stream that uses either a {@link SaslClient} or a {@link SaslServer}
53
 * An output stream that uses either a {@link SaslClient} or a {@link SaslServer}
54
 * to process the data through these entities' security layer filter(s).
54
 * to process the data through these entities' security layer filter(s).
55
 */
55
 */
56
public class SaslOutputStream extends OutputStream
56
public class SaslOutputStream
57
    extends OutputStream
57
{
58
{
58
  private static final Logger log = Logger.getLogger(SaslOutputStream.class.getName());
59
  private static final Logger log = Logger.getLogger(SaslOutputStream.class.getName());
59
  private SaslClient client;
60
  private SaslClient client;
Lines 61-76 Link Here
61
  private int maxRawSendSize;
62
  private int maxRawSendSize;
62
  private OutputStream dest;
63
  private OutputStream dest;
63
64
64
  // Constructor(s)
65
  // -------------------------------------------------------------------------
66
67
  public SaslOutputStream(SaslClient client, OutputStream dest)
65
  public SaslOutputStream(SaslClient client, OutputStream dest)
68
      throws IOException
66
      throws IOException
69
  {
67
  {
70
    super();
68
    super();
71
69
72
    this.client = client;
70
    this.client = client;
73
    maxRawSendSize = Integer.parseInt((String) client.getNegotiatedProperty(Sasl.RAW_SEND_SIZE));
71
    String size = (String) client.getNegotiatedProperty(Sasl.RAW_SEND_SIZE);
72
    maxRawSendSize = Integer.parseInt(size);
74
    server = null;
73
    server = null;
75
    this.dest = dest;
74
    this.dest = dest;
76
  }
75
  }
Lines 81-97 Link Here
81
    super();
80
    super();
82
81
83
    this.server = server;
82
    this.server = server;
84
    maxRawSendSize = Integer.parseInt((String) server.getNegotiatedProperty(Sasl.RAW_SEND_SIZE));
83
    String size = (String) server.getNegotiatedProperty(Sasl.RAW_SEND_SIZE);
84
    maxRawSendSize = Integer.parseInt(size);
85
    client = null;
85
    client = null;
86
    this.dest = dest;
86
    this.dest = dest;
87
  }
87
  }
88
88
89
  // Class methods
90
  // -------------------------------------------------------------------------
91
92
  // Overloaded java.io.OutputStream methods
93
  // -------------------------------------------------------------------------
94
95
  public void close() throws IOException
89
  public void close() throws IOException
96
  {
90
  {
97
    dest.flush();
91
    dest.flush();
Lines 126-133 Link Here
126
      log.entering(this.getClass().getName(), "write");
120
      log.entering(this.getClass().getName(), "write");
127
    if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length)
121
    if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length)
128
        || ((off + len) < 0))
122
        || ((off + len) < 0))
129
      throw new IndexOutOfBoundsException("off=" + off
123
      throw new IndexOutOfBoundsException("off=" + off + ", len=" + len
130
                                          + ", len=" + len
131
                                          + ", b.length=" + b.length);
124
                                          + ", b.length=" + b.length);
132
    if (len == 0)
125
    if (len == 0)
133
      {
126
      {
Lines 163-176 Link Here
163
          }
156
          }
164
        length = output.length;
157
        length = output.length;
165
        result = new byte[length + 4];
158
        result = new byte[length + 4];
166
        result[0] = (byte) (length >>> 24);
159
        result[0] = (byte)(length >>> 24);
167
        result[1] = (byte) (length >>> 16);
160
        result[1] = (byte)(length >>> 16);
168
        result[2] = (byte) (length >>> 8);
161
        result[2] = (byte)(length >>> 8);
169
        result[3] = (byte) length;
162
        result[3] = (byte) length;
170
        System.arraycopy(output, 0, result, 4, length);
163
        System.arraycopy(output, 0, result, 4, length);
171
172
        dest.write(result);
164
        dest.write(result);
173
174
        off += chunckSize;
165
        off += chunckSize;
175
        len -= chunckSize;
166
        len -= chunckSize;
176
        if (Configuration.DEBUG)
167
        if (Configuration.DEBUG)
Lines 181-184 Link Here
181
    if (Configuration.DEBUG)
172
    if (Configuration.DEBUG)
182
      log.exiting(this.getClass().getName(), "write");
173
      log.exiting(this.getClass().getName(), "write");
183
  }
174
  }
184
}
175
}
(-)SaslUtil.java (-14 / +1 lines)
Lines 47-76 Link Here
47
 */
47
 */
48
public class SaslUtil
48
public class SaslUtil
49
{
49
{
50
51
  // Constants and variables
52
  // -------------------------------------------------------------------------
53
54
  // Constructor(s)
55
  // -------------------------------------------------------------------------
56
57
  private SaslUtil()
50
  private SaslUtil()
58
  {
51
  {
59
    super();
52
    super();
60
  }
53
  }
61
54
62
  // Class methods
63
  // -------------------------------------------------------------------------
64
65
  public static final boolean validEmailAddress(String address)
55
  public static final boolean validEmailAddress(String address)
66
  {
56
  {
67
    // need to do better than this
57
    // need to do better than this
68
    return (address.indexOf("@") != -1);
58
    return (address.indexOf("@") != -1);
69
  }
59
  }
70
60
71
  // Visualisation methods
72
  // -------------------------------------------------------------------------
73
74
  /** Returns the context of the designated hash as a string. */
61
  /** Returns the context of the designated hash as a string. */
75
  public static final String dump(MessageDigest md)
62
  public static final String dump(MessageDigest md)
76
  {
63
  {
Lines 85-88 Link Here
85
      }
72
      }
86
    return result;
73
    return result;
87
  }
74
  }
88
}
75
}
(-)ServerFactory.java (-56 / +20 lines)
Lines 62-114 Link Here
62
/**
62
/**
63
 * The implementation of the {@link SaslServerFactory}.
63
 * The implementation of the {@link SaslServerFactory}.
64
 */
64
 */
65
public class ServerFactory implements SaslServerFactory
65
public class ServerFactory
66
    implements SaslServerFactory
66
{
67
{
67
68
  // Constants and variables
69
  // -------------------------------------------------------------------------
70
71
  // Constructor(s)
72
  // -------------------------------------------------------------------------
73
74
  // implicit 0-arguments constructor
68
  // implicit 0-arguments constructor
75
69
76
  // Class methods
77
  // -------------------------------------------------------------------------
78
79
  public static final Set getNames()
70
  public static final Set getNames()
80
  {
71
  {
81
    return Collections.unmodifiableSet(new HashSet(
72
    return Collections.unmodifiableSet(new HashSet(Arrays.asList(getNamesInternal(null))));
82
                                                   Arrays.asList(getNamesInternal(null))));
83
  }
73
  }
84
74
85
  private static final String[] getNamesInternal(Map props)
75
  private static final String[] getNamesInternal(Map props)
86
  {
76
  {
87
    String[] all = new String[] { Registry.SASL_SRP_MECHANISM,
77
    String[] all = new String[] {
88
                                 Registry.SASL_CRAM_MD5_MECHANISM,
78
        Registry.SASL_SRP_MECHANISM,
89
                                 Registry.SASL_PLAIN_MECHANISM,
79
        Registry.SASL_CRAM_MD5_MECHANISM,
90
                                 Registry.SASL_ANONYMOUS_MECHANISM };
80
        Registry.SASL_PLAIN_MECHANISM,
91
81
        Registry.SASL_ANONYMOUS_MECHANISM };
92
    List result = new ArrayList(4);
82
    List result = new ArrayList(4);
93
    int i;
83
    int i;
94
    for (i = 0; i < all.length;)
84
    for (i = 0; i < all.length;)
95
      {
85
      result.add(all[i++]);
96
        result.add(all[i++]);
97
      }
98
99
    if (props == null)
86
    if (props == null)
100
      {
87
      return (String[]) result.toArray(new String[0]); // all
101
        return (String[]) result.toArray(new String[0]); // all
88
    if (hasPolicy(Sasl.POLICY_PASS_CREDENTIALS, props)) // none
102
      }
89
      return new String[0];
103
    if (hasPolicy(Sasl.POLICY_PASS_CREDENTIALS, props))
104
      { // none
105
        return new String[0];
106
      }
107
108
    if (hasPolicy(Sasl.POLICY_NOPLAINTEXT, props))
90
    if (hasPolicy(Sasl.POLICY_NOPLAINTEXT, props))
109
      {
91
      result.remove(Registry.SASL_PLAIN_MECHANISM);
110
        result.remove(Registry.SASL_PLAIN_MECHANISM);
111
      }
112
    if (hasPolicy(Sasl.POLICY_NOACTIVE, props))
92
    if (hasPolicy(Sasl.POLICY_NOACTIVE, props))
113
      {
93
      {
114
        result.remove(Registry.SASL_CRAM_MD5_MECHANISM);
94
        result.remove(Registry.SASL_CRAM_MD5_MECHANISM);
Lines 135-166 Link Here
135
  public static final ServerMechanism getInstance(String mechanism)
115
  public static final ServerMechanism getInstance(String mechanism)
136
  {
116
  {
137
    if (mechanism == null)
117
    if (mechanism == null)
138
      {
118
      return null;
139
        return null;
140
      }
141
    mechanism = mechanism.trim().toUpperCase();
119
    mechanism = mechanism.trim().toUpperCase();
142
    if (mechanism.equals(Registry.SASL_SRP_MECHANISM))
120
    if (mechanism.equals(Registry.SASL_SRP_MECHANISM))
143
      {
121
      return new SRPServer();
144
        return new SRPServer();
145
      }
146
    if (mechanism.equals(Registry.SASL_CRAM_MD5_MECHANISM))
122
    if (mechanism.equals(Registry.SASL_CRAM_MD5_MECHANISM))
147
      {
123
      return new CramMD5Server();
148
        return new CramMD5Server();
149
      }
150
    if (mechanism.equals(Registry.SASL_PLAIN_MECHANISM))
124
    if (mechanism.equals(Registry.SASL_PLAIN_MECHANISM))
151
      {
125
      return new PlainServer();
152
        return new PlainServer();
153
      }
154
    if (mechanism.equals(Registry.SASL_ANONYMOUS_MECHANISM))
126
    if (mechanism.equals(Registry.SASL_ANONYMOUS_MECHANISM))
155
      {
127
      return new AnonymousServer();
156
        return new AnonymousServer();
157
      }
158
    return null;
128
    return null;
159
  }
129
  }
160
130
161
  // Instance methods
162
  // -------------------------------------------------------------------------
163
164
  public SaslServer createSaslServer(String mechanism, String protocol,
131
  public SaslServer createSaslServer(String mechanism, String protocol,
165
                                     String serverName, Map props,
132
                                     String serverName, Map props,
166
                                     CallbackHandler cbh) throws SaslException
133
                                     CallbackHandler cbh) throws SaslException
Lines 170-182 Link Here
170
      {
137
      {
171
        HashMap attributes = new HashMap();
138
        HashMap attributes = new HashMap();
172
        if (props != null)
139
        if (props != null)
173
          {
140
          attributes.putAll(props);
174
            attributes.putAll(props);
175
          }
176
        attributes.put(Registry.SASL_PROTOCOL, protocol);
141
        attributes.put(Registry.SASL_PROTOCOL, protocol);
177
        attributes.put(Registry.SASL_SERVER_NAME, serverName);
142
        attributes.put(Registry.SASL_SERVER_NAME, serverName);
178
        attributes.put(Registry.SASL_CALLBACK_HANDLER, cbh);
143
        attributes.put(Registry.SASL_CALLBACK_HANDLER, cbh);
179
180
        result.init(attributes);
144
        result.init(attributes);
181
      }
145
      }
182
    return result;
146
    return result;
Lines 191-194 Link Here
191
  {
155
  {
192
    return "true".equalsIgnoreCase(String.valueOf(props.get(propertyName)));
156
    return "true".equalsIgnoreCase(String.valueOf(props.get(propertyName)));
193
  }
157
  }
194
}
158
}
(-)ServerMechanism.java (-117 / +40 lines)
Lines 45-95 Link Here
45
45
46
import javax.security.auth.callback.CallbackHandler;
46
import javax.security.auth.callback.CallbackHandler;
47
import javax.security.sasl.Sasl;
47
import javax.security.sasl.Sasl;
48
import javax.security.sasl.SaslServer;
49
import javax.security.sasl.SaslException;
48
import javax.security.sasl.SaslException;
49
import javax.security.sasl.SaslServer;
50
50
51
/**
51
/**
52
 * <p>A base class to facilitate implementing SASL server-side mechanisms.</p>
52
 * A base class to facilitate implementing SASL server-side mechanisms.
53
 */
53
 */
54
public abstract class ServerMechanism implements SaslServer
54
public abstract class ServerMechanism
55
    implements SaslServer
55
{
56
{
56
57
  // Constants and variables
58
  // -------------------------------------------------------------------------
59
60
  /** Name of this mechanism. */
57
  /** Name of this mechanism. */
61
  protected String mechanism;
58
  protected String mechanism;
62
63
  /** Name of protocol using this mechanism. */
59
  /** Name of protocol using this mechanism. */
64
  protected String protocol;
60
  protected String protocol;
65
66
  /** Name of server to authenticate to. */
61
  /** Name of server to authenticate to. */
67
  protected String serverName;
62
  protected String serverName;
68
69
  /** Properties of qualities desired for this mechanism. */
63
  /** Properties of qualities desired for this mechanism. */
70
  protected Map properties;
64
  protected Map properties;
71
72
  /** Callback handler to use with this mechanism instance. */
65
  /** Callback handler to use with this mechanism instance. */
73
  protected CallbackHandler handler;
66
  protected CallbackHandler handler;
74
75
  /** Whether authentication phase is completed (true) or not (false). */
67
  /** Whether authentication phase is completed (true) or not (false). */
76
  protected boolean complete = false;
68
  protected boolean complete = false;
77
78
  /** The authorisation identity. */
69
  /** The authorisation identity. */
79
  protected String authorizationID;
70
  protected String authorizationID;
80
81
  /** Channel binding data to use with this mechanism instance. */
71
  /** Channel binding data to use with this mechanism instance. */
82
  protected byte[] channelBinding;
72
  protected byte[] channelBinding;
83
84
  /** The state of the authentication automaton. -1 means uninitialised. */
73
  /** The state of the authentication automaton. -1 means uninitialised. */
85
  protected int state = -1;
74
  protected int state = -1;
86
87
  /** The provider for authentication information. */
75
  /** The provider for authentication information. */
88
  protected IAuthInfoProvider authenticator;
76
  protected IAuthInfoProvider authenticator;
89
77
90
  // Constructor(s)
91
  // -------------------------------------------------------------------------
92
93
  protected ServerMechanism(final String mechanism)
78
  protected ServerMechanism(final String mechanism)
94
  {
79
  {
95
    super();
80
    super();
Lines 99-118 Link Here
99
    this.state = -1;
84
    this.state = -1;
100
  }
85
  }
101
86
102
  // Class methods
103
  // -------------------------------------------------------------------------
104
105
  // Instance methods
106
  // -------------------------------------------------------------------------
107
108
  // abstract methods to be implemented by concrete subclasses ---------------
109
110
  protected abstract void initMechanism() throws SaslException;
87
  protected abstract void initMechanism() throws SaslException;
111
88
112
  protected abstract void resetMechanism() throws SaslException;
89
  protected abstract void resetMechanism() throws SaslException;
113
90
114
  // javax.security.sasl.SaslServer interface implementation -----------------
115
116
  public abstract byte[] evaluateResponse(byte[] response) throws SaslException;
91
  public abstract byte[] evaluateResponse(byte[] response) throws SaslException;
117
92
118
  public boolean isComplete()
93
  public boolean isComplete()
Lines 123-142 Link Here
123
  public byte[] unwrap(final byte[] incoming, final int offset, final int len)
98
  public byte[] unwrap(final byte[] incoming, final int offset, final int len)
124
      throws SaslException
99
      throws SaslException
125
  {
100
  {
126
    if (!isComplete())
101
    if (! isComplete())
127
      {
102
      throw new IllegalMechanismStateException();
128
        throw new IllegalMechanismStateException();
129
      }
130
    return this.engineUnwrap(incoming, offset, len);
103
    return this.engineUnwrap(incoming, offset, len);
131
  }
104
  }
132
105
133
  public byte[] wrap(final byte[] outgoing, final int offset, final int len)
106
  public byte[] wrap(final byte[] outgoing, final int offset, final int len)
134
      throws SaslException
107
      throws SaslException
135
  {
108
  {
136
    if (!isComplete())
109
    if (! isComplete())
137
      {
110
      throw new IllegalMechanismStateException();
138
        throw new IllegalMechanismStateException();
139
      }
140
    return this.engineWrap(outgoing, offset, len);
111
    return this.engineWrap(outgoing, offset, len);
141
  }
112
  }
142
113
Lines 152-209 Link Here
152
123
153
  public Object getNegotiatedProperty(final String propName)
124
  public Object getNegotiatedProperty(final String propName)
154
  {
125
  {
155
    if (!isComplete())
126
    if (! isComplete())
156
      {
127
      throw new IllegalStateException();
157
        throw new IllegalStateException();
158
      }
159
    if (Sasl.QOP.equals(propName))
128
    if (Sasl.QOP.equals(propName))
160
      {
129
      return getNegotiatedQOP();
161
        return getNegotiatedQOP();
162
      }
163
    if (Sasl.STRENGTH.equals(propName))
130
    if (Sasl.STRENGTH.equals(propName))
164
      {
131
      return getNegotiatedStrength();
165
        return getNegotiatedStrength();
166
      }
167
    if (Sasl.SERVER_AUTH.equals(propName))
132
    if (Sasl.SERVER_AUTH.equals(propName))
168
      {
133
      return getNegotiatedServerAuth();
169
        return getNegotiatedServerAuth();
170
      }
171
    if (Sasl.MAX_BUFFER.equals(propName))
134
    if (Sasl.MAX_BUFFER.equals(propName))
172
      {
135
      return getNegotiatedMaxBuffer();
173
        return getNegotiatedMaxBuffer();
174
      }
175
    if (Sasl.RAW_SEND_SIZE.equals(propName))
136
    if (Sasl.RAW_SEND_SIZE.equals(propName))
176
      {
137
      return getNegotiatedRawSendSize();
177
        return getNegotiatedRawSendSize();
178
      }
179
    if (Sasl.POLICY_NOPLAINTEXT.equals(propName))
138
    if (Sasl.POLICY_NOPLAINTEXT.equals(propName))
180
      {
139
      return getNegotiatedPolicyNoPlainText();
181
        return getNegotiatedPolicyNoPlainText();
182
      }
183
    if (Sasl.POLICY_NOACTIVE.equals(propName))
140
    if (Sasl.POLICY_NOACTIVE.equals(propName))
184
      {
141
      return getNegotiatedPolicyNoActive();
185
        return getNegotiatedPolicyNoActive();
186
      }
187
    if (Sasl.POLICY_NODICTIONARY.equals(propName))
142
    if (Sasl.POLICY_NODICTIONARY.equals(propName))
188
      {
143
      return getNegotiatedPolicyNoDictionary();
189
        return getNegotiatedPolicyNoDictionary();
190
      }
191
    if (Sasl.POLICY_NOANONYMOUS.equals(propName))
144
    if (Sasl.POLICY_NOANONYMOUS.equals(propName))
192
      {
145
      return getNegotiatedPolicyNoAnonymous();
193
        return getNegotiatedPolicyNoAnonymous();
194
      }
195
    if (Sasl.POLICY_FORWARD_SECRECY.equals(propName))
146
    if (Sasl.POLICY_FORWARD_SECRECY.equals(propName))
196
      {
147
      return getNegotiatedPolicyForwardSecrecy();
197
        return getNegotiatedPolicyForwardSecrecy();
198
      }
199
    if (Sasl.POLICY_PASS_CREDENTIALS.equals(propName))
148
    if (Sasl.POLICY_PASS_CREDENTIALS.equals(propName))
200
      {
149
      return getNegotiatedPolicyPassCredentials();
201
        return getNegotiatedPolicyPassCredentials();
202
      }
203
    if (Sasl.REUSE.equals(propName))
150
    if (Sasl.REUSE.equals(propName))
204
      {
151
      return getReuse();
205
        return getReuse();
206
      }
207
    return null;
152
    return null;
208
  }
153
  }
209
154
Lines 212-219 Link Here
212
    reset();
157
    reset();
213
  }
158
  }
214
159
215
  // other Instance methods --------------------------------------------------
216
217
  protected String getNegotiatedQOP()
160
  protected String getNegotiatedQOP()
218
  {
161
  {
219
    return Registry.QOP_AUTH;
162
    return Registry.QOP_AUTH;
Lines 291-320 Link Here
291
  }
234
  }
292
235
293
  /**
236
  /**
294
   * <p>Initialises the mechanism with designated attributes. Permissible names
237
   * Initialises the mechanism with designated attributes. Permissible names and
295
   * and values are mechanism specific.</p>
238
   * values are mechanism specific.
296
   *
239
   * 
297
   * @param attributes a set of name-value pairs that describes the desired
240
   * @param attributes a set of name-value pairs that describes the desired
298
   * future behaviour of this instance.
241
   *          future behaviour of this instance.
299
   * @throws IllegalMechanismStateException if the instance is already
242
   * @throws IllegalMechanismStateException if the instance is already
300
   * initialised.
243
   *           initialised.
301
   * @throws SaslException if an exception occurs during the process.
244
   * @throws SaslException if an exception occurs during the process.
302
   */
245
   */
303
  public void init(final Map attributes) throws SaslException
246
  public void init(final Map attributes) throws SaslException
304
  {
247
  {
305
    if (state != -1)
248
    if (state != -1)
306
      {
249
      throw new IllegalMechanismStateException("init()");
307
        throw new IllegalMechanismStateException("init()");
308
      }
309
310
    if (properties == null)
250
    if (properties == null)
311
      {
251
      properties = new HashMap();
312
        properties = new HashMap();
313
      }
314
    else
252
    else
315
      {
253
      properties.clear();
316
        properties.clear();
317
      }
318
    if (attributes != null)
254
    if (attributes != null)
319
      {
255
      {
320
        protocol = (String) attributes.get(Registry.SASL_PROTOCOL);
256
        protocol = (String) attributes.get(Registry.SASL_PROTOCOL);
Lines 324-358 Link Here
324
        properties.putAll(attributes);
260
        properties.putAll(attributes);
325
      }
261
      }
326
    else
262
    else
327
      {
263
      handler = null;
328
        handler = null;
329
      }
330
331
    if (protocol == null)
264
    if (protocol == null)
332
      {
265
      protocol = "";
333
        protocol = "";
334
      }
335
    if (serverName == null)
266
    if (serverName == null)
336
      {
267
      serverName = "";
337
        serverName = "";
338
      }
339
    if (authenticator != null)
268
    if (authenticator != null)
340
      {
269
      authenticator.activate(properties);
341
        authenticator.activate(properties);
342
      }
343
    if (channelBinding == null)
270
    if (channelBinding == null)
344
      {
271
      channelBinding = new byte[0];
345
        channelBinding = new byte[0];
346
      }
347
    initMechanism();
272
    initMechanism();
348
    complete = false;
273
    complete = false;
349
    state = 0;
274
    state = 0;
350
  }
275
  }
351
276
352
  /**
277
  /**
353
   * <p>Resets the mechanism instance for re-initialisation and use with other
278
   * Resets the mechanism instance for re-initialisation and use with other
354
   * characteristics.</p>
279
   * characteristics.
355
   *
280
   * 
356
   * @throws SaslException if an exception occurs during the process.
281
   * @throws SaslException if an exception occurs during the process.
357
   */
282
   */
358
  public void reset() throws SaslException
283
  public void reset() throws SaslException
Lines 360-371 Link Here
360
    resetMechanism();
285
    resetMechanism();
361
    properties.clear();
286
    properties.clear();
362
    if (authenticator != null)
287
    if (authenticator != null)
363
      {
288
      authenticator.passivate();
364
        authenticator.passivate();
365
      }
366
    protocol = serverName = null;
289
    protocol = serverName = null;
367
    channelBinding = null;
290
    channelBinding = null;
368
    complete = false;
291
    complete = false;
369
    state = -1;
292
    state = -1;
370
  }
293
  }
371
}
294
}
(-)UserAlreadyExistsException.java (-3 / +3 lines)
Lines 44-52 Link Here
44
 * A checked exception thrown to indicate that a designated user is already
44
 * A checked exception thrown to indicate that a designated user is already
45
 * known to the the authentication layer.
45
 * known to the the authentication layer.
46
 */
46
 */
47
public class UserAlreadyExistsException extends SaslException
47
public class UserAlreadyExistsException
48
    extends SaslException
48
{
49
{
49
50
  /**
50
  /**
51
   * Constructs a <code>UserAlreadyExistsException</code> with no detail
51
   * Constructs a <code>UserAlreadyExistsException</code> with no detail
52
   * message.
52
   * message.
Lines 60-66 Link Here
60
   * Constructs a <code>UserAlreadyExistsException</code> with the specified
60
   * Constructs a <code>UserAlreadyExistsException</code> with the specified
61
   * detail message. In the case of this exception, the detail message
61
   * detail message. In the case of this exception, the detail message
62
   * designates the offending username.
62
   * designates the offending username.
63
   *
63
   * 
64
   * @param userName the detail message, which in this case is the username.
64
   * @param userName the detail message, which in this case is the username.
65
   */
65
   */
66
  public UserAlreadyExistsException(String userName)
66
  public UserAlreadyExistsException(String userName)
(-)anonymous/AnonymousClient.java (-27 / +9 lines)
Lines 44-78 Link Here
44
44
45
import java.io.UnsupportedEncodingException;
45
import java.io.UnsupportedEncodingException;
46
46
47
import javax.security.sasl.AuthenticationException;
47
import javax.security.sasl.SaslClient;
48
import javax.security.sasl.SaslClient;
48
import javax.security.sasl.SaslException;
49
import javax.security.sasl.SaslException;
49
import javax.security.sasl.AuthenticationException;
50
50
51
/**
51
/**
52
 * <p>The ANONYMOUS client-side mechanism.</p>
52
 * The ANONYMOUS client-side mechanism.
53
 */
53
 */
54
public class AnonymousClient extends ClientMechanism implements SaslClient
54
public class AnonymousClient
55
    extends ClientMechanism
56
    implements SaslClient
55
{
57
{
56
57
  // Constants and variables
58
  // -------------------------------------------------------------------------
59
60
  // Constructor(s)
61
  // -------------------------------------------------------------------------
62
63
  public AnonymousClient()
58
  public AnonymousClient()
64
  {
59
  {
65
    super(Registry.SASL_ANONYMOUS_MECHANISM);
60
    super(Registry.SASL_ANONYMOUS_MECHANISM);
66
  }
61
  }
67
62
68
  // Class methods
69
  // -------------------------------------------------------------------------
70
71
  // Instance methods
72
  // -------------------------------------------------------------------------
73
74
  // abstract methods implementation -----------------------------------------
75
76
  protected void initMechanism() throws SaslException
63
  protected void initMechanism() throws SaslException
77
  {
64
  {
78
  }
65
  }
Lines 81-88 Link Here
81
  {
68
  {
82
  }
69
  }
83
70
84
  // javax.security.sasl.SaslClient interface implementation -----------------
85
86
  public boolean hasInitialResponse()
71
  public boolean hasInitialResponse()
87
  {
72
  {
88
    return true;
73
    return true;
Lines 99-111 Link Here
99
84
100
  private byte[] response() throws SaslException
85
  private byte[] response() throws SaslException
101
  {
86
  {
102
    if (!AnonymousUtil.isValidTraceInformation(authorizationID))
87
    if (! AnonymousUtil.isValidTraceInformation(authorizationID))
103
      {
88
      throw new AuthenticationException(
104
        throw new AuthenticationException(
89
          "Authorisation ID is not a valid email address");
105
                                          "Authorisation ID is not a valid email address");
106
      }
107
    complete = true;
90
    complete = true;
108
    //      return authorizationID.getBytes();
109
    final byte[] result;
91
    final byte[] result;
110
    try
92
    try
111
      {
93
      {
Lines 117-120 Link Here
117
      }
99
      }
118
    return result;
100
    return result;
119
  }
101
  }
120
}
102
}
(-)anonymous/AnonymousServer.java (-22 / +5 lines)
Lines 50-77 Link Here
50
/**
50
/**
51
 * The ANONYMOUS server-side mechanism.
51
 * The ANONYMOUS server-side mechanism.
52
 */
52
 */
53
public class AnonymousServer extends ServerMechanism implements SaslServer
53
public class AnonymousServer
54
    extends ServerMechanism
55
    implements SaslServer
54
{
56
{
55
56
  // Constants and variables
57
  // -------------------------------------------------------------------------
58
59
  // Constructor(s)
60
  // -------------------------------------------------------------------------
61
62
  public AnonymousServer()
57
  public AnonymousServer()
63
  {
58
  {
64
    super(Registry.SASL_ANONYMOUS_MECHANISM);
59
    super(Registry.SASL_ANONYMOUS_MECHANISM);
65
  }
60
  }
66
61
67
  // Class methods
68
  // -------------------------------------------------------------------------
69
70
  // Instance methods
71
  // -------------------------------------------------------------------------
72
73
  // abstract methods implementation -----------------------------------------
74
75
  protected void initMechanism() throws SaslException
62
  protected void initMechanism() throws SaslException
76
  {
63
  {
77
  }
64
  }
Lines 80-93 Link Here
80
  {
67
  {
81
  }
68
  }
82
69
83
  // javax.security.sasl.SaslServer interface implementation -----------------
84
85
  public byte[] evaluateResponse(final byte[] response) throws SaslException
70
  public byte[] evaluateResponse(final byte[] response) throws SaslException
86
  {
71
  {
87
    if (response == null)
72
    if (response == null)
88
      {
73
      return null;
89
        return null;
90
      }
91
    try
74
    try
92
      {
75
      {
93
        authorizationID = new String(response, "UTF-8");
76
        authorizationID = new String(response, "UTF-8");
Lines 104-107 Link Here
104
    authorizationID = null;
87
    authorizationID = null;
105
    throw new AuthenticationException("Invalid email address");
88
    throw new AuthenticationException("Invalid email address");
106
  }
89
  }
107
}
90
}
(-)anonymous/AnonymousUtil.java (-35 / +9 lines)
Lines 45-109 Link Here
45
 */
45
 */
46
public class AnonymousUtil
46
public class AnonymousUtil
47
{
47
{
48
49
  // Constants and variables
50
  // -------------------------------------------------------------------------
51
52
  // Constructor(s)
53
  // -------------------------------------------------------------------------
54
55
  /** Trivial private constructor to enforce Singleton pattern. */
48
  /** Trivial private constructor to enforce Singleton pattern. */
56
  private AnonymousUtil()
49
  private AnonymousUtil()
57
  {
50
  {
58
    super();
51
    super();
59
  }
52
  }
60
53
61
  // Class methods
62
  // -------------------------------------------------------------------------
63
64
  static boolean isValidTraceInformation(String traceInformation)
54
  static boolean isValidTraceInformation(String traceInformation)
65
  {
55
  {
66
    if (traceInformation == null)
56
    if (traceInformation == null)
67
      {
57
      return false;
68
        return false;
69
      }
70
    if (traceInformation.length() == 0)
58
    if (traceInformation.length() == 0)
71
      {
59
      return true;
72
        return true;
73
      }
74
    if (SaslUtil.validEmailAddress(traceInformation))
60
    if (SaslUtil.validEmailAddress(traceInformation))
75
      {
61
      return true;
76
        return true;
77
      }
78
    return isValidToken(traceInformation);
62
    return isValidToken(traceInformation);
79
  }
63
  }
80
64
81
  static boolean isValidToken(String token)
65
  static boolean isValidToken(String token)
82
  {
66
  {
83
    if (token == null)
67
    if (token == null)
84
      {
68
      return false;
85
        return false;
86
      }
87
    if (token.length() == 0)
69
    if (token.length() == 0)
88
      {
70
      return false;
89
        return false;
90
      }
91
    if (token.length() > 255)
71
    if (token.length() > 255)
92
      {
72
      return false;
93
        return false;
94
      }
95
    if (token.indexOf('@') != -1)
73
    if (token.indexOf('@') != -1)
96
      {
74
      return false;
97
        return false;
98
      }
99
    for (int i = 0; i < token.length(); i++)
75
    for (int i = 0; i < token.length(); i++)
100
      {
76
      {
101
        char c = token.charAt(i);
77
        char c = token.charAt(i);
102
        if (c < 0x20 || c > 0x7E)
78
        if (c < 0x20 || c > 0x7E)
103
          {
79
          return false;
104
            return false;
105
          }
106
      }
80
      }
107
    return true;
81
    return true;
108
  }
82
  }
109
}
83
}
(-)crammd5/CramMD5AuthInfoProvider.java (-48 / +14 lines)
Lines 51-94 Link Here
51
/**
51
/**
52
 * The CRAM-MD5 mechanism authentication information provider implementation.
52
 * The CRAM-MD5 mechanism authentication information provider implementation.
53
 */
53
 */
54
public class CramMD5AuthInfoProvider implements IAuthInfoProvider
54
public class CramMD5AuthInfoProvider
55
    implements IAuthInfoProvider
55
{
56
{
56
57
  // Constants and variables
58
  // -------------------------------------------------------------------------
59
60
  private PasswordFile passwordFile = null;
57
  private PasswordFile passwordFile = null;
61
58
62
  // Constructor(s)
63
  // -------------------------------------------------------------------------
64
65
  // implicit 0-args constrcutor
59
  // implicit 0-args constrcutor
66
60
67
  // Class methods
68
  // -------------------------------------------------------------------------
69
70
  // IAuthInfoProvider interface implementation
71
  // -------------------------------------------------------------------------
72
73
  public void activate(Map context) throws AuthenticationException
61
  public void activate(Map context) throws AuthenticationException
74
  {
62
  {
75
    try
63
    try
76
      {
64
      {
77
        if (context == null)
65
        if (context == null)
78
          {
66
          passwordFile = new PasswordFile();
79
            passwordFile = new PasswordFile();
80
          }
81
        else
67
        else
82
          {
68
          {
83
            String pfn = (String) context.get(CramMD5Registry.PASSWORD_FILE);
69
            String pfn = (String) context.get(CramMD5Registry.PASSWORD_FILE);
84
            if (pfn == null)
70
            if (pfn == null)
85
              {
71
              passwordFile = new PasswordFile();
86
                passwordFile = new PasswordFile();
87
              }
88
            else
72
            else
89
              {
73
              passwordFile = new PasswordFile(pfn);
90
                passwordFile = new PasswordFile(pfn);
91
              }
92
          }
74
          }
93
      }
75
      }
94
    catch (IOException x)
76
    catch (IOException x)
Lines 105-114 Link Here
105
  public boolean contains(String userName) throws AuthenticationException
87
  public boolean contains(String userName) throws AuthenticationException
106
  {
88
  {
107
    if (passwordFile == null)
89
    if (passwordFile == null)
108
      {
90
      throw new AuthenticationException("contains()",
109
        throw new AuthenticationException("contains()",
91
                                        new IllegalStateException());
110
                                          new IllegalStateException());
111
      }
112
    boolean result = false;
92
    boolean result = false;
113
    try
93
    try
114
      {
94
      {
Lines 124-141 Link Here
124
  public Map lookup(Map userID) throws AuthenticationException
104
  public Map lookup(Map userID) throws AuthenticationException
125
  {
105
  {
126
    if (passwordFile == null)
106
    if (passwordFile == null)
127
      {
107
      throw new AuthenticationException("lookup()", new IllegalStateException());
128
        throw new AuthenticationException("lookup()",
129
                                          new IllegalStateException());
130
      }
131
    Map result = new HashMap();
108
    Map result = new HashMap();
132
    try
109
    try
133
      {
110
      {
134
        String userName = (String) userID.get(Registry.SASL_USERNAME);
111
        String userName = (String) userID.get(Registry.SASL_USERNAME);
135
        if (userName == null)
112
        if (userName == null)
136
          {
113
          throw new NoSuchUserException("");
137
            throw new NoSuchUserException("");
138
          }
139
        String[] data = passwordFile.lookup(userName);
114
        String[] data = passwordFile.lookup(userName);
140
        result.put(Registry.SASL_USERNAME, data[0]);
115
        result.put(Registry.SASL_USERNAME, data[0]);
141
        result.put(Registry.SASL_PASSWORD, data[1]);
116
        result.put(Registry.SASL_PASSWORD, data[1]);
Lines 148-156 Link Here
148
    catch (Exception x)
123
    catch (Exception x)
149
      {
124
      {
150
        if (x instanceof AuthenticationException)
125
        if (x instanceof AuthenticationException)
151
          {
126
          throw (AuthenticationException) x;
152
            throw (AuthenticationException) x;
153
          }
154
        throw new AuthenticationException("lookup()", x);
127
        throw new AuthenticationException("lookup()", x);
155
      }
128
      }
156
    return result;
129
    return result;
Lines 159-168 Link Here
159
  public void update(Map userCredentials) throws AuthenticationException
132
  public void update(Map userCredentials) throws AuthenticationException
160
  {
133
  {
161
    if (passwordFile == null)
134
    if (passwordFile == null)
162
      {
135
      throw new AuthenticationException("update()", new IllegalStateException());
163
        throw new AuthenticationException("update()",
164
                                          new IllegalStateException());
165
      }
166
    try
136
    try
167
      {
137
      {
168
        String userName = (String) userCredentials.get(Registry.SASL_USERNAME);
138
        String userName = (String) userCredentials.get(Registry.SASL_USERNAME);
Lines 174-182 Link Here
174
        String shell = (String) userCredentials.get(CramMD5Registry.SHELL_FIELD);
144
        String shell = (String) userCredentials.get(CramMD5Registry.SHELL_FIELD);
175
        if (uid == null || gid == null || gecos == null || dir == null
145
        if (uid == null || gid == null || gecos == null || dir == null
176
            || shell == null)
146
            || shell == null)
177
          {
147
          passwordFile.changePasswd(userName, password);
178
            passwordFile.changePasswd(userName, password);
179
          }
180
        else
148
        else
181
          {
149
          {
182
            String[] attributes = new String[] { uid, gid, gecos, dir, shell };
150
            String[] attributes = new String[] { uid, gid, gecos, dir, shell };
Lines 186-194 Link Here
186
    catch (Exception x)
154
    catch (Exception x)
187
      {
155
      {
188
        if (x instanceof AuthenticationException)
156
        if (x instanceof AuthenticationException)
189
          {
157
          throw (AuthenticationException) x;
190
            throw (AuthenticationException) x;
191
          }
192
        throw new AuthenticationException("update()", x);
158
        throw new AuthenticationException("update()", x);
193
      }
159
      }
194
  }
160
  }
Lines 197-200 Link Here
197
  {
163
  {
198
    throw new AuthenticationException("", new UnsupportedOperationException());
164
    throw new AuthenticationException("", new UnsupportedOperationException());
199
  }
165
  }
200
}
166
}
(-)crammd5/CramMD5Client.java (-48 / +15 lines)
Lines 56-80 Link Here
56
/**
56
/**
57
 * The CRAM-MD5 SASL client-side mechanism.
57
 * The CRAM-MD5 SASL client-side mechanism.
58
 */
58
 */
59
public class CramMD5Client extends ClientMechanism implements SaslClient
59
public class CramMD5Client
60
    extends ClientMechanism
61
    implements SaslClient
60
{
62
{
61
62
  // Constants and variables
63
  // -------------------------------------------------------------------------
64
65
  // Constructor(s)
66
  // -------------------------------------------------------------------------
67
68
  public CramMD5Client()
63
  public CramMD5Client()
69
  {
64
  {
70
    super(Registry.SASL_CRAM_MD5_MECHANISM);
65
    super(Registry.SASL_CRAM_MD5_MECHANISM);
71
  }
66
  }
72
67
73
  // Class methods
74
  // -------------------------------------------------------------------------
75
76
  // abstract methods implementation -----------------------------------------
77
78
  protected void initMechanism() throws SaslException
68
  protected void initMechanism() throws SaslException
79
  {
69
  {
80
  }
70
  }
Lines 83-90 Link Here
83
  {
73
  {
84
  }
74
  }
85
75
86
  // javax.security.sasl.SaslClient interface implementation -----------------
87
88
  public boolean hasInitialResponse()
76
  public boolean hasInitialResponse()
89
  {
77
  {
90
    return false;
78
    return false;
Lines 93-122 Link Here
93
  public byte[] evaluateChallenge(final byte[] challenge) throws SaslException
81
  public byte[] evaluateChallenge(final byte[] challenge) throws SaslException
94
  {
82
  {
95
    if (challenge == null)
83
    if (challenge == null)
96
      {
84
      throw new SaslException("null challenge");
97
        throw new SaslException("null challenge");
98
      }
99
    try
85
    try
100
      {
86
      {
101
        final String username;
87
        final String username;
102
        final char[] password;
88
        final char[] password;
103
        Callback[] callbacks;
89
        Callback[] callbacks;
104
90
        if ((! properties.containsKey(Registry.SASL_USERNAME))
105
        if ((!properties.containsKey(Registry.SASL_USERNAME))
91
            && (! properties.containsKey(Registry.SASL_PASSWORD)))
106
            && (!properties.containsKey(Registry.SASL_PASSWORD)))
107
          {
92
          {
108
            callbacks = new Callback[2];
93
            callbacks = new Callback[2];
109
110
            final NameCallback nameCB;
94
            final NameCallback nameCB;
111
            final String defaultName = System.getProperty("user.name");
95
            final String defaultName = System.getProperty("user.name");
112
            if (defaultName == null)
96
            if (defaultName == null)
113
              {
97
              nameCB = new NameCallback("username: ");
114
                nameCB = new NameCallback("username: ");
115
              }
116
            else
98
            else
117
              {
99
              nameCB = new NameCallback("username: ", defaultName);
118
                nameCB = new NameCallback("username: ", defaultName);
119
              }
120
            final PasswordCallback pwdCB = new PasswordCallback("password: ",
100
            final PasswordCallback pwdCB = new PasswordCallback("password: ",
121
                                                                false);
101
                                                                false);
122
            callbacks[0] = nameCB;
102
            callbacks[0] = nameCB;
Lines 128-174 Link Here
128
        else
108
        else
129
          {
109
          {
130
            if (properties.containsKey(Registry.SASL_USERNAME))
110
            if (properties.containsKey(Registry.SASL_USERNAME))
131
              {
111
              username = (String) properties.get(Registry.SASL_USERNAME);
132
                username = (String) properties.get(Registry.SASL_USERNAME);
133
              }
134
            else
112
            else
135
              {
113
              {
136
                callbacks = new Callback[1];
114
                callbacks = new Callback[1];
137
                final NameCallback nameCB;
115
                final NameCallback nameCB;
138
                final String defaultName = System.getProperty("user.name");
116
                final String defaultName = System.getProperty("user.name");
139
                if (defaultName == null)
117
                if (defaultName == null)
140
                  {
118
                  nameCB = new NameCallback("username: ");
141
                    nameCB = new NameCallback("username: ");
142
                  }
143
                else
119
                else
144
                  {
120
                  nameCB = new NameCallback("username: ", defaultName);
145
                    nameCB = new NameCallback("username: ", defaultName);
146
                  }
147
                callbacks[0] = nameCB;
121
                callbacks[0] = nameCB;
148
                this.handler.handle(callbacks);
122
                this.handler.handle(callbacks);
149
                username = nameCB.getName();
123
                username = nameCB.getName();
150
              }
124
              }
151
125
152
            if (properties.containsKey(Registry.SASL_PASSWORD))
126
            if (properties.containsKey(Registry.SASL_PASSWORD))
153
              {
127
              password = ((String) properties.get(Registry.SASL_PASSWORD)).toCharArray();
154
                password = ((String) properties.get(Registry.SASL_PASSWORD)).toCharArray();
155
              }
156
            else
128
            else
157
              {
129
              {
158
                callbacks = new Callback[1];
130
                callbacks = new Callback[1];
159
                final PasswordCallback pwdCB = new PasswordCallback(
131
                final PasswordCallback pwdCB = new PasswordCallback("password: ",
160
                                                                    "password: ",
161
                                                                    false);
132
                                                                    false);
162
                callbacks[0] = pwdCB;
133
                callbacks[0] = pwdCB;
163
                this.handler.handle(callbacks);
134
                this.handler.handle(callbacks);
164
                password = pwdCB.getPassword();
135
                password = pwdCB.getPassword();
165
              }
136
              }
166
          }
137
          }
167
168
        if (password == null)
138
        if (password == null)
169
          {
139
          throw new SaslException("null password supplied");
170
            throw new SaslException("null password supplied");
171
          }
172
        final byte[] digest;
140
        final byte[] digest;
173
        try
141
        try
174
          {
142
          {
Lines 181-187 Link Here
181
        final String response = username + " "
149
        final String response = username + " "
182
                                + Util.toString(digest).toLowerCase();
150
                                + Util.toString(digest).toLowerCase();
183
        this.complete = true;
151
        this.complete = true;
184
185
        return response.getBytes("UTF-8");
152
        return response.getBytes("UTF-8");
186
      }
153
      }
187
    catch (UnsupportedCallbackException x)
154
    catch (UnsupportedCallbackException x)
Lines 198-201 Link Here
198
  {
165
  {
199
    return Registry.QOP_AUTH;
166
    return Registry.QOP_AUTH;
200
  }
167
  }
201
}
168
}
(-)crammd5/CramMD5Registry.java (-7 / +1 lines)
Lines 45-66 Link Here
45
{
45
{
46
  /** Name of the password file (used by the server) property. */
46
  /** Name of the password file (used by the server) property. */
47
  String PASSWORD_FILE = "gnu.crypto.sasl.crammd5.password.file";
47
  String PASSWORD_FILE = "gnu.crypto.sasl.crammd5.password.file";
48
49
  /** Default password file (used by the server) pathname. */
48
  /** Default password file (used by the server) pathname. */
50
  String DEFAULT_PASSWORD_FILE = "/etc/passwd";
49
  String DEFAULT_PASSWORD_FILE = "/etc/passwd";
51
52
  /** Name of the UID field in the plain password file. */
50
  /** Name of the UID field in the plain password file. */
53
  String UID_FIELD = "crammd5.uid";
51
  String UID_FIELD = "crammd5.uid";
54
55
  /** Name of the GID field in the plain password file. */
52
  /** Name of the GID field in the plain password file. */
56
  String GID_FIELD = "crammd5.gid";
53
  String GID_FIELD = "crammd5.gid";
57
58
  /** Name of the GECOS field in the plain password file. */
54
  /** Name of the GECOS field in the plain password file. */
59
  String GECOS_FIELD = "crammd5.gecos";
55
  String GECOS_FIELD = "crammd5.gecos";
60
61
  /** Name of the DIR field in the plain password file. */
56
  /** Name of the DIR field in the plain password file. */
62
  String DIR_FIELD = "crammd5.dir";
57
  String DIR_FIELD = "crammd5.dir";
63
64
  /** Name of the SHELL field in the plain password file. */
58
  /** Name of the SHELL field in the plain password file. */
65
  String SHELL_FIELD = "crammd5.shell";
59
  String SHELL_FIELD = "crammd5.shell";
66
}
60
}
(-)crammd5/CramMD5Server.java (-39 / +12 lines)
Lines 55-83 Link Here
55
import javax.security.sasl.SaslServer;
55
import javax.security.sasl.SaslServer;
56
56
57
/**
57
/**
58
 * <p>The CRAM-MD5 SASL server-side mechanism.</p>
58
 * The CRAM-MD5 SASL server-side mechanism.
59
 */
59
 */
60
public class CramMD5Server extends ServerMechanism implements SaslServer
60
public class CramMD5Server
61
    extends ServerMechanism
62
    implements SaslServer
61
{
63
{
62
63
  // Constants and variables
64
  // -------------------------------------------------------------------------
65
66
  private byte[] msgID;
64
  private byte[] msgID;
67
65
68
  // Constructor(s)
69
  // -------------------------------------------------------------------------
70
71
  public CramMD5Server()
66
  public CramMD5Server()
72
  {
67
  {
73
    super(Registry.SASL_CRAM_MD5_MECHANISM);
68
    super(Registry.SASL_CRAM_MD5_MECHANISM);
74
  }
69
  }
75
70
76
  // Class methods
77
  // -------------------------------------------------------------------------
78
79
  // abstract methods implementation -----------------------------------------
80
81
  protected void initMechanism() throws SaslException
71
  protected void initMechanism() throws SaslException
82
  {
72
  {
83
  }
73
  }
Lines 86-93 Link Here
86
  {
76
  {
87
  }
77
  }
88
78
89
  // javax.security.sasl.SaslServer interface implementation -----------------
90
91
  public byte[] evaluateResponse(final byte[] response) throws SaslException
79
  public byte[] evaluateResponse(final byte[] response) throws SaslException
92
  {
80
  {
93
    if (state == 0)
81
    if (state == 0)
Lines 96-102 Link Here
96
        state++;
84
        state++;
97
        return msgID;
85
        return msgID;
98
      }
86
      }
99
100
    final String responseStr = new String(response);
87
    final String responseStr = new String(response);
101
    final int index = responseStr.lastIndexOf(" ");
88
    final int index = responseStr.lastIndexOf(" ");
102
    final String username = responseStr.substring(0, index);
89
    final String username = responseStr.substring(0, index);
Lines 109-118 Link Here
109
      {
96
      {
110
        throw new AuthenticationException("evaluateResponse()", x);
97
        throw new AuthenticationException("evaluateResponse()", x);
111
      }
98
      }
112
113
    // Look up the password
99
    // Look up the password
114
    final char[] password = lookupPassword(username);
100
    final char[] password = lookupPassword(username);
115
116
    // Compute the digest
101
    // Compute the digest
117
    byte[] digest;
102
    byte[] digest;
118
    try
103
    try
Lines 125-143 Link Here
125
      }
110
      }
126
    try
111
    try
127
      {
112
      {
128
        //         digest = (new String(Util.toString(digest).toLowerCase())).getBytes("UTF-8");
129
        digest = Util.toString(digest).toLowerCase().getBytes("UTF-8");
113
        digest = Util.toString(digest).toLowerCase().getBytes("UTF-8");
130
      }
114
      }
131
    catch (UnsupportedEncodingException x)
115
    catch (UnsupportedEncodingException x)
132
      {
116
      {
133
        throw new AuthenticationException("evaluateResponse()", x);
117
        throw new AuthenticationException("evaluateResponse()", x);
134
      }
118
      }
135
136
    // Compare the received and computed digests
119
    // Compare the received and computed digests
137
    if (!Arrays.equals(digest, responseDigest))
120
    if (! Arrays.equals(digest, responseDigest))
138
      {
121
      throw new AuthenticationException("Digest mismatch");
139
        throw new AuthenticationException("Digest mismatch");
140
      }
141
    state++;
122
    state++;
142
    return null;
123
    return null;
143
  }
124
  }
Lines 152-185 Link Here
152
    return Registry.QOP_AUTH;
133
    return Registry.QOP_AUTH;
153
  }
134
  }
154
135
155
  // Other instance methods --------------------------------------------------
156
157
  private char[] lookupPassword(final String userName) throws SaslException
136
  private char[] lookupPassword(final String userName) throws SaslException
158
  {
137
  {
159
    try
138
    try
160
      {
139
      {
161
        if (!authenticator.contains(userName))
140
        if (! authenticator.contains(userName))
162
          {
141
          throw new NoSuchUserException(userName);
163
            throw new NoSuchUserException(userName);
164
          }
165
        final Map userID = new HashMap();
142
        final Map userID = new HashMap();
166
        userID.put(Registry.SASL_USERNAME, userName);
143
        userID.put(Registry.SASL_USERNAME, userName);
167
        final Map credentials = authenticator.lookup(userID);
144
        final Map credentials = authenticator.lookup(userID);
168
        final String password = (String) credentials.get(Registry.SASL_PASSWORD);
145
        final String password = (String) credentials.get(Registry.SASL_PASSWORD);
169
        if (password == null)
146
        if (password == null)
170
          {
147
          throw new AuthenticationException("lookupPassword()",
171
            throw new AuthenticationException("lookupPassword()",
148
                                            new InternalError());
172
                                              new InternalError());
173
          }
174
        return password.toCharArray();
149
        return password.toCharArray();
175
      }
150
      }
176
    catch (IOException x)
151
    catch (IOException x)
177
      {
152
      {
178
        if (x instanceof SaslException)
153
        if (x instanceof SaslException)
179
          {
154
          throw (SaslException) x;
180
            throw (SaslException) x;
181
          }
182
        throw new AuthenticationException("lookupPassword()", x);
155
        throw new AuthenticationException("lookupPassword()", x);
183
      }
156
      }
184
  }
157
  }
185
}
158
}
(-)crammd5/CramMD5Util.java (-25 / +8 lines)
Lines 56-84 Link Here
56
 */
56
 */
57
class CramMD5Util
57
class CramMD5Util
58
{
58
{
59
60
  // Constants and variables
61
  // -------------------------------------------------------------------------
62
63
  // Constructor(s)
64
  // -------------------------------------------------------------------------
65
66
  private CramMD5Util()
59
  private CramMD5Util()
67
  {
60
  {
68
    super();
61
    super();
69
  }
62
  }
70
63
71
  // Class methods
72
  // -------------------------------------------------------------------------
73
74
  static byte[] createMsgID() throws SaslException
64
  static byte[] createMsgID() throws SaslException
75
  {
65
  {
76
    // <process-ID.clock@hostname>
77
    final String encoded;
66
    final String encoded;
78
    try
67
    try
79
      {
68
      {
80
        encoded = Util.toBase64(Thread.currentThread().getName().getBytes(
69
        encoded = Util.toBase64(Thread.currentThread().getName().getBytes("UTF-8"));
81
                                                                          "UTF-8"));
82
      }
70
      }
83
    catch (UnsupportedEncodingException x)
71
    catch (UnsupportedEncodingException x)
84
      {
72
      {
Lines 92-111 Link Here
92
    catch (UnknownHostException ignored)
80
    catch (UnknownHostException ignored)
93
      {
81
      {
94
      }
82
      }
95
96
    final byte[] result;
83
    final byte[] result;
97
    try
84
    try
98
      {
85
      {
99
        result = new StringBuffer().append("<").append(
86
        result = new StringBuffer("<")
100
                                                       encoded.substring(
87
            .append(encoded.substring(0,encoded.length()))
101
                                                                         0,
88
            .append(".").append(String.valueOf(System.currentTimeMillis()))
102
                                                                         encoded.length())).append(
89
            .append("@").append(hostname).append(">")
103
                                                                                                   ".").append(
90
            .toString()
104
                                                                                                               String.valueOf(System.currentTimeMillis())).append(
91
            .getBytes("UTF-8");
105
                                                                                                                                                                  "@").append(
106
                                                                                                                                                                              hostname).append(
107
                                                                                                                                                                                               ">").toString().getBytes(
108
                                                                                                                                                                                                                        "UTF-8");
109
      }
92
      }
110
    catch (UnsupportedEncodingException x)
93
    catch (UnsupportedEncodingException x)
111
      {
94
      {
Lines 134-137 Link Here
134
    mac.update(data, 0, data.length);
117
    mac.update(data, 0, data.length);
135
    return mac.digest();
118
    return mac.digest();
136
  }
119
  }
137
}
120
}
(-)crammd5/PasswordFile.java (-92 / +29 lines)
Lines 59-84 Link Here
59
 */
59
 */
60
public class PasswordFile
60
public class PasswordFile
61
{
61
{
62
63
  // Constants and variables
64
  // -------------------------------------------------------------------------
65
66
  private static String DEFAULT_FILE;
62
  private static String DEFAULT_FILE;
67
  static
63
  static
68
    {
64
    {
69
      DEFAULT_FILE = System.getProperty(CramMD5Registry.PASSWORD_FILE,
65
      DEFAULT_FILE = System.getProperty(CramMD5Registry.PASSWORD_FILE,
70
                                        CramMD5Registry.DEFAULT_PASSWORD_FILE);
66
                                        CramMD5Registry.DEFAULT_PASSWORD_FILE);
71
    }
67
    }
72
73
  private HashMap entries;
68
  private HashMap entries;
74
75
  private File passwdFile;
69
  private File passwdFile;
76
77
  private long lastmod;
70
  private long lastmod;
78
71
79
  // Constructor(s)
80
  // -------------------------------------------------------------------------
81
82
  public PasswordFile() throws IOException
72
  public PasswordFile() throws IOException
83
  {
73
  {
84
    this(DEFAULT_FILE);
74
    this(DEFAULT_FILE);
Lines 95-119 Link Here
95
    update();
85
    update();
96
  }
86
  }
97
87
98
  // Class methods
99
  // -------------------------------------------------------------------------
100
101
  // Instance methods
102
  // -------------------------------------------------------------------------
103
104
  public synchronized void add(final String user, final String passwd,
88
  public synchronized void add(final String user, final String passwd,
105
                               final String[] attributes) throws IOException
89
                               final String[] attributes) throws IOException
106
  {
90
  {
107
    checkCurrent(); // check if the entry exists
91
    checkCurrent(); // check if the entry exists
108
    if (entries.containsKey(user))
92
    if (entries.containsKey(user))
109
      {
93
      throw new UserAlreadyExistsException(user);
110
        throw new UserAlreadyExistsException(user);
111
      }
112
    if (attributes.length != 5)
94
    if (attributes.length != 5)
113
      {
95
      throw new IllegalArgumentException("Wrong number of attributes");
114
        throw new IllegalArgumentException("Wrong number of attributes");
115
      }
116
117
    final String[] fields = new String[7]; // create the new entry
96
    final String[] fields = new String[7]; // create the new entry
118
    fields[0] = user;
97
    fields[0] = user;
119
    fields[1] = passwd;
98
    fields[1] = passwd;
Lines 126-158 Link Here
126
      throws IOException
105
      throws IOException
127
  {
106
  {
128
    checkCurrent();
107
    checkCurrent();
129
    if (!entries.containsKey(user))
108
    if (! entries.containsKey(user))
130
      { // check if the entry exists
109
      throw new NoSuchUserException(user);
131
        throw new NoSuchUserException(user);
110
    final String[] fields = (String[]) entries.get(user); // get existing entry
132
      }
133
134
    final String[] fields = (String[]) entries.get(user); // get the existing entry
135
    fields[1] = passwd; // modify the password field
111
    fields[1] = passwd; // modify the password field
136
    entries.remove(user); // delete the existing entry
112
    entries.remove(user); // delete the existing entry
137
    entries.put(user, fields); // add the new entry
113
    entries.put(user, fields); // add the new entry
138
139
    savePasswd();
114
    savePasswd();
140
  }
115
  }
141
116
142
  public synchronized String[] lookup(final String user) throws IOException
117
  public synchronized String[] lookup(final String user) throws IOException
143
  {
118
  {
144
    checkCurrent();
119
    checkCurrent();
145
    if (!entries.containsKey(user))
120
    if (! entries.containsKey(user))
146
      {
121
      throw new NoSuchUserException(user);
147
        throw new NoSuchUserException(user);
148
      }
149
    return (String[]) entries.get(user);
122
    return (String[]) entries.get(user);
150
  }
123
  }
151
124
152
  public synchronized boolean contains(final String s) throws IOException
125
  public synchronized boolean contains(final String s) throws IOException
153
  {
126
  {
154
    checkCurrent();
127
    checkCurrent();
155
156
    return entries.containsKey(s);
128
    return entries.containsKey(s);
157
  }
129
  }
158
130
Lines 165-173 Link Here
165
  private void checkCurrent() throws IOException
137
  private void checkCurrent() throws IOException
166
  {
138
  {
167
    if (passwdFile.lastModified() > lastmod)
139
    if (passwdFile.lastModified() > lastmod)
168
      {
140
      update();
169
        update();
170
      }
171
  }
141
  }
172
142
173
  private synchronized void readPasswd(final InputStream in) throws IOException
143
  private synchronized void readPasswd(final InputStream in) throws IOException
Lines 183-250 Link Here
183
          {
153
          {
184
            fields[0] = st.nextToken(); // username
154
            fields[0] = st.nextToken(); // username
185
            st.nextToken();
155
            st.nextToken();
186
187
            fields[1] = st.nextToken(); // passwd
156
            fields[1] = st.nextToken(); // passwd
188
            if (fields[1].equals(":"))
157
            if (fields[1].equals(":"))
189
              {
158
              fields[1] = "";
190
                fields[1] = "";
191
              }
192
            else
159
            else
193
              {
160
              st.nextToken();
194
                st.nextToken();
195
              }
196
197
            fields[2] = st.nextToken(); // uid
161
            fields[2] = st.nextToken(); // uid
198
            if (fields[2].equals(":"))
162
            if (fields[2].equals(":"))
199
              {
163
              fields[2] = "";
200
                fields[2] = "";
201
              }
202
            else
164
            else
203
              {
165
              st.nextToken();
204
                st.nextToken();
205
              }
206
207
            fields[3] = st.nextToken(); // gid
166
            fields[3] = st.nextToken(); // gid
208
            if (fields[3].equals(":"))
167
            if (fields[3].equals(":"))
209
              {
168
              fields[3] = "";
210
                fields[3] = "";
211
              }
212
            else
169
            else
213
              {
170
              st.nextToken();
214
                st.nextToken();
215
              }
216
217
            fields[4] = st.nextToken(); // gecos
171
            fields[4] = st.nextToken(); // gecos
218
            if (fields[4].equals(":"))
172
            if (fields[4].equals(":"))
219
              {
173
              fields[4] = "";
220
                fields[4] = "";
221
              }
222
            else
174
            else
223
              {
175
              st.nextToken();
224
                st.nextToken();
225
              }
226
227
            fields[5] = st.nextToken(); // dir
176
            fields[5] = st.nextToken(); // dir
228
            if (fields[5].equals(":"))
177
            if (fields[5].equals(":"))
229
              {
178
              fields[5] = "";
230
                fields[5] = "";
231
              }
232
            else
179
            else
233
              {
180
              st.nextToken();
234
                st.nextToken();
235
              }
236
237
            fields[6] = st.nextToken(); // shell
181
            fields[6] = st.nextToken(); // shell
238
            if (fields[6].equals(":"))
182
            if (fields[6].equals(":"))
239
              {
183
              fields[6] = "";
240
                fields[6] = "";
241
              }
242
          }
184
          }
243
        catch (NoSuchElementException x)
185
        catch (NoSuchElementException x)
244
          {
186
          {
245
            continue;
187
            continue;
246
          }
188
          }
247
248
        entries.put(fields[0], fields);
189
        entries.put(fields[0], fields);
249
      }
190
      }
250
  }
191
  }
Lines 268-292 Link Here
268
                fields = (String[]) entries.get(key);
209
                fields = (String[]) entries.get(key);
269
                sb = new StringBuffer(fields[0]);
210
                sb = new StringBuffer(fields[0]);
270
                for (i = 1; i < fields.length; i++)
211
                for (i = 1; i < fields.length; i++)
271
                  {
212
                  sb.append(":").append(fields[i]);
272
                    sb.append(":").append(fields[i]);
273
                  }
274
                pw.println(sb.toString());
213
                pw.println(sb.toString());
275
              }
214
              }
276
          }
215
          }
277
        finally
216
        finally
278
          {
217
          {
279
            if (pw != null)
218
            if (pw != null)
280
              {
219
              try
281
                try
220
                {
282
                  {
221
                  pw.flush();
283
                    pw.flush();
222
                }
284
                  }
223
              finally
285
                finally
224
                {
286
                  {
225
                  pw.close();
287
                    pw.close();
226
                }
288
                  }
289
              }
290
            try
227
            try
291
              {
228
              {
292
                fos.close();
229
                fos.close();
Lines 298-301 Link Here
298
          }
235
          }
299
      }
236
      }
300
  }
237
  }
301
}
238
}
(-)plain/PasswordFile.java (-105 / +37 lines)
Lines 39-45 Link Here
39
package gnu.javax.crypto.sasl.plain;
39
package gnu.javax.crypto.sasl.plain;
40
40
41
import gnu.classpath.SystemProperties;
41
import gnu.classpath.SystemProperties;
42
43
import gnu.javax.crypto.sasl.NoSuchUserException;
42
import gnu.javax.crypto.sasl.NoSuchUserException;
44
import gnu.javax.crypto.sasl.UserAlreadyExistsException;
43
import gnu.javax.crypto.sasl.UserAlreadyExistsException;
45
44
Lines 47-87 Link Here
47
import java.io.File;
46
import java.io.File;
48
import java.io.FileInputStream;
47
import java.io.FileInputStream;
49
import java.io.FileOutputStream;
48
import java.io.FileOutputStream;
49
import java.io.IOException;
50
import java.io.InputStream;
50
import java.io.InputStream;
51
import java.io.InputStreamReader;
51
import java.io.InputStreamReader;
52
import java.io.IOException;
53
import java.io.PrintWriter;
52
import java.io.PrintWriter;
54
import java.util.Enumeration;
53
import java.util.Enumeration;
55
import java.util.Hashtable;
54
import java.util.Hashtable;
56
import java.util.StringTokenizer;
57
import java.util.NoSuchElementException;
55
import java.util.NoSuchElementException;
56
import java.util.StringTokenizer;
58
57
59
/**
58
/**
60
 * A representation of a Plain password file.
59
 * A representation of a Plain password file.
61
 */
60
 */
62
public class PasswordFile
61
public class PasswordFile
63
{
62
{
64
65
  // Constants and variables
66
  // -------------------------------------------------------------------------
67
68
  private static String DEFAULT_FILE;
63
  private static String DEFAULT_FILE;
69
  static
64
  static
70
    {
65
    {
71
      DEFAULT_FILE = SystemProperties.getProperty(PlainRegistry.PASSWORD_FILE,
66
      DEFAULT_FILE = SystemProperties.getProperty(PlainRegistry.PASSWORD_FILE,
72
                                                  PlainRegistry.DEFAULT_PASSWORD_FILE);
67
                                                  PlainRegistry.DEFAULT_PASSWORD_FILE);
73
    }
68
    }
74
75
  private Hashtable entries;
69
  private Hashtable entries;
76
77
  private File passwdFile;
70
  private File passwdFile;
78
79
  //   private String[] last_params;
80
  private long lastmod;
71
  private long lastmod;
81
72
82
  // Constructor(s)
83
  // -------------------------------------------------------------------------
84
85
  public PasswordFile() throws IOException
73
  public PasswordFile() throws IOException
86
  {
74
  {
87
    this(DEFAULT_FILE);
75
    this(DEFAULT_FILE);
Lines 98-128 Link Here
98
    update();
86
    update();
99
  }
87
  }
100
88
101
  // Class methods
102
  // -------------------------------------------------------------------------
103
104
  // Instance methods
105
  // -------------------------------------------------------------------------
106
107
  public synchronized void add(String user, String passwd, String[] attributes)
89
  public synchronized void add(String user, String passwd, String[] attributes)
108
      throws IOException
90
      throws IOException
109
  {
91
  {
110
    checkCurrent();
92
    checkCurrent();
111
    if (entries.containsKey(user))
93
    if (entries.containsKey(user))
112
      {
94
      throw new UserAlreadyExistsException(user);
113
        throw new UserAlreadyExistsException(user);
114
      }
115
    if (attributes.length != 5)
95
    if (attributes.length != 5)
116
      {
96
      throw new IllegalArgumentException("Wrong number of attributes");
117
        throw new IllegalArgumentException("Wrong number of attributes");
118
      }
119
    // create the new entry
97
    // create the new entry
120
    String[] fields = new String[7];
98
    String[] fields = new String[7];
121
    fields[0] = user;
99
    fields[0] = user;
122
    fields[1] = passwd;
100
    fields[1] = passwd;
123
    System.arraycopy(attributes, 0, fields, 2, 5);
101
    System.arraycopy(attributes, 0, fields, 2, 5);
124
    entries.put(user, fields);
102
    entries.put(user, fields);
125
126
    savePasswd();
103
    savePasswd();
127
  }
104
  }
128
105
Lines 130-155 Link Here
130
      throws IOException
107
      throws IOException
131
  {
108
  {
132
    checkCurrent();
109
    checkCurrent();
133
    if (!entries.containsKey(user))
110
    if (! entries.containsKey(user))
134
      {
111
      throw new NoSuchUserException(user);
135
        throw new NoSuchUserException(user);
136
      }
137
138
    String[] fields = (String[]) entries.get(user); // get the existing entry
112
    String[] fields = (String[]) entries.get(user); // get the existing entry
139
    fields[1] = passwd; // modify the password field
113
    fields[1] = passwd; // modify the password field
140
    entries.remove(user); // delete the existing entry
114
    entries.remove(user); // delete the existing entry
141
    entries.put(user, fields); // add the new entry
115
    entries.put(user, fields); // add the new entry
142
143
    savePasswd();
116
    savePasswd();
144
  }
117
  }
145
118
146
  public synchronized String[] lookup(String user) throws IOException
119
  public synchronized String[] lookup(String user) throws IOException
147
  {
120
  {
148
    checkCurrent();
121
    checkCurrent();
149
    if (!entries.containsKey(user))
122
    if (! entries.containsKey(user))
150
      {
123
      throw new NoSuchUserException(user);
151
        throw new NoSuchUserException(user);
152
      }
153
    return (String[]) entries.get(user);
124
    return (String[]) entries.get(user);
154
  }
125
  }
155
126
Lines 159-166 Link Here
159
    return entries.containsKey(s);
130
    return entries.containsKey(s);
160
  }
131
  }
161
132
162
  //----------------------------------------------------------------//
163
164
  private synchronized void update() throws IOException
133
  private synchronized void update() throws IOException
165
  {
134
  {
166
    lastmod = passwdFile.lastModified();
135
    lastmod = passwdFile.lastModified();
Lines 170-178 Link Here
170
  private void checkCurrent() throws IOException
139
  private void checkCurrent() throws IOException
171
  {
140
  {
172
    if (passwdFile.lastModified() > lastmod)
141
    if (passwdFile.lastModified() > lastmod)
173
      {
142
      update();
174
        update();
175
      }
176
  }
143
  }
177
144
178
  private synchronized void readPasswd(InputStream in) throws IOException
145
  private synchronized void readPasswd(InputStream in) throws IOException
Lines 188-255 Link Here
188
          {
155
          {
189
            fields[0] = st.nextToken(); // username
156
            fields[0] = st.nextToken(); // username
190
            st.nextToken();
157
            st.nextToken();
191
192
            fields[1] = st.nextToken(); // passwd
158
            fields[1] = st.nextToken(); // passwd
193
            if (fields[1].equals(":"))
159
            if (fields[1].equals(":"))
194
              {
160
              fields[1] = "";
195
                fields[1] = "";
196
              }
197
            else
161
            else
198
              {
162
              st.nextToken();
199
                st.nextToken();
200
              }
201
202
            fields[2] = st.nextToken(); // uid
163
            fields[2] = st.nextToken(); // uid
203
            if (fields[2].equals(":"))
164
            if (fields[2].equals(":"))
204
              {
165
              fields[2] = "";
205
                fields[2] = "";
206
              }
207
            else
166
            else
208
              {
167
              st.nextToken();
209
                st.nextToken();
210
              }
211
212
            fields[3] = st.nextToken(); // gid
168
            fields[3] = st.nextToken(); // gid
213
            if (fields[3].equals(":"))
169
            if (fields[3].equals(":"))
214
              {
170
              fields[3] = "";
215
                fields[3] = "";
216
              }
217
            else
171
            else
218
              {
172
              st.nextToken();
219
                st.nextToken();
220
              }
221
222
            fields[4] = st.nextToken(); // gecos
173
            fields[4] = st.nextToken(); // gecos
223
            if (fields[4].equals(":"))
174
            if (fields[4].equals(":"))
224
              {
175
              fields[4] = "";
225
                fields[4] = "";
226
              }
227
            else
176
            else
228
              {
177
              st.nextToken();
229
                st.nextToken();
230
              }
231
232
            fields[5] = st.nextToken(); // dir
178
            fields[5] = st.nextToken(); // dir
233
            if (fields[5].equals(":"))
179
            if (fields[5].equals(":"))
234
              {
180
              fields[5] = "";
235
                fields[5] = "";
236
              }
237
            else
181
            else
238
              {
182
              st.nextToken();
239
                st.nextToken();
240
              }
241
242
            fields[6] = st.nextToken(); // shell
183
            fields[6] = st.nextToken(); // shell
243
            if (fields[6].equals(":"))
184
            if (fields[6].equals(":"))
244
              {
185
              fields[6] = "";
245
                fields[6] = "";
246
              }
247
          }
186
          }
248
        catch (NoSuchElementException ignored)
187
        catch (NoSuchElementException ignored)
249
          {
188
          {
250
            continue;
189
            continue;
251
          }
190
          }
252
253
        entries.put(fields[0], fields);
191
        entries.put(fields[0], fields);
254
      }
192
      }
255
  }
193
  }
Lines 273-309 Link Here
273
                fields = (String[]) entries.get(key);
211
                fields = (String[]) entries.get(key);
274
                sb = new StringBuffer(fields[0]);
212
                sb = new StringBuffer(fields[0]);
275
                for (int i = 1; i < fields.length; i++)
213
                for (int i = 1; i < fields.length; i++)
276
                  {
214
                  sb.append(":" + fields[i]);
277
                    sb.append(":" + fields[i]);
278
                  }
279
                pw.println(sb.toString());
215
                pw.println(sb.toString());
280
              }
216
              }
281
          }
217
          }
282
        finally
218
        finally
283
          {
219
          {
284
            if (pw != null)
220
            if (pw != null)
285
              {
221
              try
286
                try
222
                {
287
                  {
223
                  pw.flush();
288
                    pw.flush();
224
                }
289
                  }
225
              finally
290
                finally
226
                {
291
                  {
227
                  pw.close();
292
                    pw.close();
228
                }
293
                  }
294
              }
295
            if (fos != null)
229
            if (fos != null)
296
              {
230
              try
297
                try
231
                {
298
                  {
232
                  fos.close();
299
                    fos.close();
233
                }
300
                  }
234
              catch (IOException ignored)
301
                catch (IOException ignored)
235
                {
302
                  {
236
                }
303
                  }
304
              }
305
            lastmod = passwdFile.lastModified();
237
            lastmod = passwdFile.lastModified();
306
          }
238
          }
307
      }
239
      }
308
  }
240
  }
309
}
241
}
(-)plain/PlainAuthInfoProvider.java (-56 / +16 lines)
Lines 51-94 Link Here
51
/**
51
/**
52
 * The PLAIN mechanism authentication information provider implementation.
52
 * The PLAIN mechanism authentication information provider implementation.
53
 */
53
 */
54
public class PlainAuthInfoProvider implements IAuthInfoProvider, PlainRegistry
54
public class PlainAuthInfoProvider
55
    implements IAuthInfoProvider, PlainRegistry
55
{
56
{
56
57
  // Constants and variables
58
  // -------------------------------------------------------------------------
59
60
  private PasswordFile passwordFile = null;
57
  private PasswordFile passwordFile = null;
61
58
62
  // Constructor(s)
63
  // -------------------------------------------------------------------------
64
65
  // implicit 0-args constrcutor
59
  // implicit 0-args constrcutor
66
60
67
  // Class methods
68
  // -------------------------------------------------------------------------
69
70
  // IAuthInfoProvider interface implementation
71
  // -------------------------------------------------------------------------
72
73
  public void activate(Map context) throws AuthenticationException
61
  public void activate(Map context) throws AuthenticationException
74
  {
62
  {
75
    try
63
    try
76
      {
64
      {
77
        if (context == null)
65
        if (context == null)
78
          {
66
          passwordFile = new PasswordFile();
79
            passwordFile = new PasswordFile();
80
          }
81
        else
67
        else
82
          {
68
          {
83
            String pfn = (String) context.get(PASSWORD_FILE);
69
            String pfn = (String) context.get(PASSWORD_FILE);
84
            if (pfn == null)
70
            if (pfn == null)
85
              {
71
              passwordFile = new PasswordFile();
86
                passwordFile = new PasswordFile();
87
              }
88
            else
72
            else
89
              {
73
              passwordFile = new PasswordFile(pfn);
90
                passwordFile = new PasswordFile(pfn);
91
              }
92
          }
74
          }
93
      }
75
      }
94
    catch (IOException x)
76
    catch (IOException x)
Lines 105-114 Link Here
105
  public boolean contains(String userName) throws AuthenticationException
87
  public boolean contains(String userName) throws AuthenticationException
106
  {
88
  {
107
    if (passwordFile == null)
89
    if (passwordFile == null)
108
      {
90
      throw new AuthenticationException("contains()",
109
        throw new AuthenticationException("contains()",
91
                                        new IllegalStateException());
110
                                          new IllegalStateException());
111
      }
112
    boolean result = false;
92
    boolean result = false;
113
    try
93
    try
114
      {
94
      {
Lines 124-141 Link Here
124
  public Map lookup(Map userID) throws AuthenticationException
104
  public Map lookup(Map userID) throws AuthenticationException
125
  {
105
  {
126
    if (passwordFile == null)
106
    if (passwordFile == null)
127
      {
107
      throw new AuthenticationException("lookup()", new IllegalStateException());
128
        throw new AuthenticationException("lookup()",
129
                                          new IllegalStateException());
130
      }
131
    Map result = new HashMap();
108
    Map result = new HashMap();
132
    try
109
    try
133
      {
110
      {
134
        String userName = (String) userID.get(Registry.SASL_USERNAME);
111
        String userName = (String) userID.get(Registry.SASL_USERNAME);
135
        if (userName == null)
112
        if (userName == null)
136
          {
113
          throw new NoSuchUserException("");
137
            throw new NoSuchUserException("");
138
          }
139
        String[] data = passwordFile.lookup(userName);
114
        String[] data = passwordFile.lookup(userName);
140
        result.put(Registry.SASL_USERNAME, data[0]);
115
        result.put(Registry.SASL_USERNAME, data[0]);
141
        result.put(Registry.SASL_PASSWORD, data[1]);
116
        result.put(Registry.SASL_PASSWORD, data[1]);
Lines 148-160 Link Here
148
    catch (Exception x)
123
    catch (Exception x)
149
      {
124
      {
150
        if (x instanceof AuthenticationException)
125
        if (x instanceof AuthenticationException)
151
          {
126
          throw (AuthenticationException) x;
152
            throw (AuthenticationException) x;
127
        throw new AuthenticationException("lookup()", x);
153
          }
154
        else
155
          {
156
            throw new AuthenticationException("lookup()", x);
157
          }
158
      }
128
      }
159
    return result;
129
    return result;
160
  }
130
  }
Lines 162-171 Link Here
162
  public void update(Map userCredentials) throws AuthenticationException
132
  public void update(Map userCredentials) throws AuthenticationException
163
  {
133
  {
164
    if (passwordFile == null)
134
    if (passwordFile == null)
165
      {
135
      throw new AuthenticationException("update()", new IllegalStateException());
166
        throw new AuthenticationException("update()",
167
                                          new IllegalStateException());
168
      }
169
    try
136
    try
170
      {
137
      {
171
        String userName = (String) userCredentials.get(Registry.SASL_USERNAME);
138
        String userName = (String) userCredentials.get(Registry.SASL_USERNAME);
Lines 177-185 Link Here
177
        String shell = (String) userCredentials.get(SHELL_FIELD);
144
        String shell = (String) userCredentials.get(SHELL_FIELD);
178
        if (uid == null || gid == null || gecos == null || dir == null
145
        if (uid == null || gid == null || gecos == null || dir == null
179
            || shell == null)
146
            || shell == null)
180
          {
147
          passwordFile.changePasswd(userName, password);
181
            passwordFile.changePasswd(userName, password);
182
          }
183
        else
148
        else
184
          {
149
          {
185
            String[] attributes = new String[] { uid, gid, gecos, dir, shell };
150
            String[] attributes = new String[] { uid, gid, gecos, dir, shell };
Lines 189-201 Link Here
189
    catch (Exception x)
154
    catch (Exception x)
190
      {
155
      {
191
        if (x instanceof AuthenticationException)
156
        if (x instanceof AuthenticationException)
192
          {
157
          throw (AuthenticationException) x;
193
            throw (AuthenticationException) x;
158
        throw new AuthenticationException("update()", x);
194
          }
195
        else
196
          {
197
            throw new AuthenticationException("update()", x);
198
          }
199
      }
159
      }
200
  }
160
  }
201
161
Lines 203-206 Link Here
203
  {
163
  {
204
    throw new AuthenticationException("", new UnsupportedOperationException());
164
    throw new AuthenticationException("", new UnsupportedOperationException());
205
  }
165
  }
206
}
166
}
(-)plain/PlainClient.java (-56 / +17 lines)
Lines 48-77 Link Here
48
import javax.security.auth.callback.PasswordCallback;
48
import javax.security.auth.callback.PasswordCallback;
49
49
50
/**
50
/**
51
 * <p>The PLAIN SASL client-side mechanism.</p>
51
 * The PLAIN SASL client-side mechanism.
52
 */
52
 */
53
public class PlainClient extends ClientMechanism implements SaslClient
53
public class PlainClient
54
    extends ClientMechanism
55
    implements SaslClient
54
{
56
{
55
56
  // Constants and variables
57
  // -------------------------------------------------------------------------
58
59
  // Constructor(s)
60
  // -------------------------------------------------------------------------
61
62
  public PlainClient()
57
  public PlainClient()
63
  {
58
  {
64
    super(Registry.SASL_PLAIN_MECHANISM);
59
    super(Registry.SASL_PLAIN_MECHANISM);
65
  }
60
  }
66
61
67
  // Class methods
68
  // -------------------------------------------------------------------------
69
70
  // Instance methods
71
  // -------------------------------------------------------------------------
72
73
  // abstract methods implementation -----------------------------------------
74
75
  protected void initMechanism() throws SaslException
62
  protected void initMechanism() throws SaslException
76
  {
63
  {
77
  }
64
  }
Lines 80-87 Link Here
80
  {
67
  {
81
  }
68
  }
82
69
83
  // javax.security.sasl.SaslClient interface implementation -----------------
84
85
  public boolean hasInitialResponse()
70
  public boolean hasInitialResponse()
86
  {
71
  {
87
    return true;
72
    return true;
Lines 94-115 Link Here
94
        final String username;
79
        final String username;
95
        final char[] password;
80
        final char[] password;
96
        Callback[] callbacks;
81
        Callback[] callbacks;
97
82
        if ((! properties.containsKey(Registry.SASL_USERNAME))
98
        if ((!properties.containsKey(Registry.SASL_USERNAME))
83
            && (! properties.containsKey(Registry.SASL_PASSWORD)))
99
            && (!properties.containsKey(Registry.SASL_PASSWORD)))
100
          {
84
          {
101
            callbacks = new Callback[2];
85
            callbacks = new Callback[2];
102
103
            final NameCallback nameCB;
86
            final NameCallback nameCB;
104
            final String defaultName = System.getProperty("user.name");
87
            final String defaultName = System.getProperty("user.name");
105
            if (defaultName == null)
88
            if (defaultName == null)
106
              {
89
              nameCB = new NameCallback("username: ");
107
                nameCB = new NameCallback("username: ");
108
              }
109
            else
90
            else
110
              {
91
              nameCB = new NameCallback("username: ", defaultName);
111
                nameCB = new NameCallback("username: ", defaultName);
112
              }
113
            final PasswordCallback pwdCB = new PasswordCallback("password: ",
92
            final PasswordCallback pwdCB = new PasswordCallback("password: ",
114
                                                                false);
93
                                                                false);
115
            callbacks[0] = nameCB;
94
            callbacks[0] = nameCB;
Lines 121-187 Link Here
121
        else
100
        else
122
          {
101
          {
123
            if (properties.containsKey(Registry.SASL_USERNAME))
102
            if (properties.containsKey(Registry.SASL_USERNAME))
124
              {
103
              username = (String) properties.get(Registry.SASL_USERNAME);
125
                username = (String) properties.get(Registry.SASL_USERNAME);
126
              }
127
            else
104
            else
128
              {
105
              {
129
                callbacks = new Callback[1];
106
                callbacks = new Callback[1];
130
                final NameCallback nameCB;
107
                final NameCallback nameCB;
131
                final String defaultName = System.getProperty("user.name");
108
                final String defaultName = System.getProperty("user.name");
132
                if (defaultName == null)
109
                if (defaultName == null)
133
                  {
110
                  nameCB = new NameCallback("username: ");
134
                    nameCB = new NameCallback("username: ");
135
                  }
136
                else
111
                else
137
                  {
112
                  nameCB = new NameCallback("username: ", defaultName);
138
                    nameCB = new NameCallback("username: ", defaultName);
139
                  }
140
                callbacks[0] = nameCB;
113
                callbacks[0] = nameCB;
141
                this.handler.handle(callbacks);
114
                this.handler.handle(callbacks);
142
                username = nameCB.getName();
115
                username = nameCB.getName();
143
              }
116
              }
144
145
            if (properties.containsKey(Registry.SASL_PASSWORD))
117
            if (properties.containsKey(Registry.SASL_PASSWORD))
146
              {
118
              password = ((String) properties.get(Registry.SASL_PASSWORD)).toCharArray();
147
                password = ((String) properties.get(Registry.SASL_PASSWORD)).toCharArray();
148
              }
149
            else
119
            else
150
              {
120
              {
151
                callbacks = new Callback[1];
121
                callbacks = new Callback[1];
152
                final PasswordCallback pwdCB = new PasswordCallback(
122
                final PasswordCallback pwdCB = new PasswordCallback("password: ",
153
                                                                    "password: ",
154
                                                                    false);
123
                                                                    false);
155
                callbacks[0] = pwdCB;
124
                callbacks[0] = pwdCB;
156
                this.handler.handle(callbacks);
125
                this.handler.handle(callbacks);
157
                password = pwdCB.getPassword();
126
                password = pwdCB.getPassword();
158
              }
127
              }
159
          }
128
          }
160
161
        if (password == null)
129
        if (password == null)
162
          {
130
          throw new SaslException("null password supplied");
163
            throw new SaslException("null password supplied");
164
          }
165
        final StringBuffer sb = new StringBuffer();
131
        final StringBuffer sb = new StringBuffer();
166
        if (authorizationID != null)
132
        if (authorizationID != null)
167
          {
133
          sb.append(authorizationID);
168
            sb.append(authorizationID);
169
          }
170
        sb.append('\0');
134
        sb.append('\0');
171
        sb.append(username);
135
        sb.append(username);
172
        sb.append('\0');
136
        sb.append('\0');
173
        sb.append(password);
137
        sb.append(password);
174
        this.complete = true;
138
        this.complete = true;
175
176
        final byte[] response = sb.toString().getBytes("UTF-8");
139
        final byte[] response = sb.toString().getBytes("UTF-8");
177
        return response;
140
        return response;
178
      }
141
      }
179
    catch (Exception x)
142
    catch (Exception x)
180
      {
143
      {
181
        if (x instanceof SaslException)
144
        if (x instanceof SaslException)
182
          {
145
          throw (SaslException) x;
183
            throw (SaslException) x;
184
          }
185
        throw new SaslException("evaluateChallenge()", x);
146
        throw new SaslException("evaluateChallenge()", x);
186
      }
147
      }
187
  }
148
  }
Lines 190-193 Link Here
190
  {
151
  {
191
    return Registry.QOP_AUTH;
152
    return Registry.QOP_AUTH;
192
  }
153
  }
193
}
154
}
(-)plain/PlainRegistry.java (-11 / +1 lines)
Lines 40-67 Link Here
40
40
41
public interface PlainRegistry
41
public interface PlainRegistry
42
{
42
{
43
44
  // Constants
45
  // -------------------------------------------------------------------------
46
47
  /** Name of PLAIN password file property. */
43
  /** Name of PLAIN password file property. */
48
  String PASSWORD_FILE = "gnu.crypto.sasl.plain.password.file";
44
  String PASSWORD_FILE = "gnu.crypto.sasl.plain.password.file";
49
50
  /** Default fully qualified pathname of the PLAIN password file. */
45
  /** Default fully qualified pathname of the PLAIN password file. */
51
  String DEFAULT_PASSWORD_FILE = "/etc/tpasswd";
46
  String DEFAULT_PASSWORD_FILE = "/etc/tpasswd";
52
53
  /** Name of the UID field in the plain password file. */
47
  /** Name of the UID field in the plain password file. */
54
  String UID_FIELD = "plain.uid";
48
  String UID_FIELD = "plain.uid";
55
56
  /** Name of the GID field in the plain password file. */
49
  /** Name of the GID field in the plain password file. */
57
  String GID_FIELD = "plain.gid";
50
  String GID_FIELD = "plain.gid";
58
59
  /** Name of the GECOS field in the plain password file. */
51
  /** Name of the GECOS field in the plain password file. */
60
  String GECOS_FIELD = "plain.gecos";
52
  String GECOS_FIELD = "plain.gecos";
61
62
  /** Name of the DIR field in the plain password file. */
53
  /** Name of the DIR field in the plain password file. */
63
  String DIR_FIELD = "plain.dir";
54
  String DIR_FIELD = "plain.dir";
64
65
  /** Name of the SHELL field in the plain password file. */
55
  /** Name of the SHELL field in the plain password file. */
66
  String SHELL_FIELD = "plain.shell";
56
  String SHELL_FIELD = "plain.shell";
67
}
57
}
(-)plain/PlainServer.java (-62 / +21 lines)
Lines 54-83 Link Here
54
import javax.security.sasl.SaslServer;
54
import javax.security.sasl.SaslServer;
55
55
56
/**
56
/**
57
 * <p>The PLAIN SASL server-side mechanism.</p>
57
 * The PLAIN SASL server-side mechanism.
58
 */
58
 */
59
public class PlainServer extends ServerMechanism implements SaslServer
59
public class PlainServer
60
    extends ServerMechanism
61
    implements SaslServer
60
{
62
{
61
62
  // Constants and variables
63
  // -------------------------------------------------------------------------
64
65
  // Constructor(s)
66
  // -------------------------------------------------------------------------
67
68
  public PlainServer()
63
  public PlainServer()
69
  {
64
  {
70
    super(Registry.SASL_PLAIN_MECHANISM);
65
    super(Registry.SASL_PLAIN_MECHANISM);
71
  }
66
  }
72
67
73
  // Class methods
74
  // -------------------------------------------------------------------------
75
76
  // Instance methods
77
  // -------------------------------------------------------------------------
78
79
  // abstract methods implementation -----------------------------------------
80
81
  protected void initMechanism() throws SaslException
68
  protected void initMechanism() throws SaslException
82
  {
69
  {
83
  }
70
  }
Lines 86-128 Link Here
86
  {
73
  {
87
  }
74
  }
88
75
89
  // javax.security.sasl.SaslServer interface implementation -----------------
90
91
  public byte[] evaluateResponse(final byte[] response) throws SaslException
76
  public byte[] evaluateResponse(final byte[] response) throws SaslException
92
  {
77
  {
93
    if (response == null)
78
    if (response == null)
94
      {
79
      return null;
95
        return null;
96
      }
97
    try
80
    try
98
      {
81
      {
99
        final String nullStr = new String("\0");
82
        final String nullStr = new String("\0");
100
        final StringTokenizer strtok = new StringTokenizer(
83
        final StringTokenizer strtok = new StringTokenizer(new String(response),
101
                                                           new String(response),
102
                                                           nullStr, true);
84
                                                           nullStr, true);
103
104
        authorizationID = strtok.nextToken();
85
        authorizationID = strtok.nextToken();
105
        if (!authorizationID.equals(nullStr))
86
        if (! authorizationID.equals(nullStr))
106
          {
87
          strtok.nextToken();
107
            strtok.nextToken();
108
          }
109
        else
88
        else
110
          {
89
          authorizationID = null;
111
            authorizationID = null;
112
          }
113
        final String id = strtok.nextToken();
90
        final String id = strtok.nextToken();
114
        if (id.equals(nullStr))
91
        if (id.equals(nullStr))
115
          {
92
          throw new SaslException("No identity given");
116
            throw new SaslException("No identity given");
117
          }
118
        if (authorizationID == null)
93
        if (authorizationID == null)
119
          {
94
          authorizationID = id;
120
            authorizationID = id;
95
        if ((! authorizationID.equals(nullStr)) && (! authorizationID.equals(id)))
121
          }
96
          throw new SaslException("Delegation not supported");
122
        if ((!authorizationID.equals(nullStr)) && (!authorizationID.equals(id)))
123
          {
124
            throw new SaslException("Delegation not supported");
125
          }
126
        strtok.nextToken();
97
        strtok.nextToken();
127
        final byte[] pwd;
98
        final byte[] pwd;
128
        try
99
        try
Lines 134-142 Link Here
134
            throw new SaslException("evaluateResponse()", x);
105
            throw new SaslException("evaluateResponse()", x);
135
          }
106
          }
136
        if (pwd == null)
107
        if (pwd == null)
137
          {
108
          throw new SaslException("No password given");
138
            throw new SaslException("No password given");
139
          }
140
        final byte[] password;
109
        final byte[] password;
141
        try
110
        try
142
          {
111
          {
Lines 146-155 Link Here
146
          {
115
          {
147
            throw new SaslException("evaluateResponse()", x);
116
            throw new SaslException("evaluateResponse()", x);
148
          }
117
          }
149
        if (!Arrays.equals(pwd, password))
118
        if (! Arrays.equals(pwd, password))
150
          {
119
          throw new SaslException("Password incorrect");
151
            throw new SaslException("Password incorrect");
152
          }
153
        this.complete = true;
120
        this.complete = true;
154
        return null;
121
        return null;
155
      }
122
      }
Lines 164-196 Link Here
164
    return Registry.QOP_AUTH;
131
    return Registry.QOP_AUTH;
165
  }
132
  }
166
133
167
  // other methods -----------------------------------------------------------
168
169
  private char[] lookupPassword(final String userName) throws SaslException
134
  private char[] lookupPassword(final String userName) throws SaslException
170
  {
135
  {
171
    try
136
    try
172
      {
137
      {
173
        if (!authenticator.contains(userName))
138
        if (! authenticator.contains(userName))
174
          {
139
          throw new NoSuchUserException(userName);
175
            throw new NoSuchUserException(userName);
176
          }
177
        final Map userID = new HashMap();
140
        final Map userID = new HashMap();
178
        userID.put(Registry.SASL_USERNAME, userName);
141
        userID.put(Registry.SASL_USERNAME, userName);
179
        final Map credentials = authenticator.lookup(userID);
142
        final Map credentials = authenticator.lookup(userID);
180
        final String password = (String) credentials.get(Registry.SASL_PASSWORD);
143
        final String password = (String) credentials.get(Registry.SASL_PASSWORD);
181
        if (password == null)
144
        if (password == null)
182
          {
145
          throw new SaslException("lookupPassword()", new InternalError());
183
            throw new SaslException("lookupPassword()", new InternalError());
184
          }
185
        return password.toCharArray();
146
        return password.toCharArray();
186
      }
147
      }
187
    catch (IOException x)
148
    catch (IOException x)
188
      {
149
      {
189
        if (x instanceof SaslException)
150
        if (x instanceof SaslException)
190
          {
151
          throw (SaslException) x;
191
            throw (SaslException) x;
192
          }
193
        throw new SaslException("lookupPassword()", x);
152
        throw new SaslException("lookupPassword()", x);
194
      }
153
      }
195
  }
154
  }
196
}
155
}
(-)srp/CALG.java (-122 / +51 lines)
Lines 58-122 Link Here
58
import javax.security.sasl.SaslException;
58
import javax.security.sasl.SaslException;
59
59
60
/**
60
/**
61
 * <p>A Factory class that returns CALG (Confidentiality Algorithm) instances
61
 * A Factory class that returns CALG (Confidentiality Algorithm) instances that
62
 * that operate as described in the draft-burdis-cat-sasl-srp-08.</p>
62
 * operate as described in the draft-burdis-cat-sasl-srp-08.
63
 *
63
 * <p>
64
 * <p>The designated CALG block cipher should be used in OFB (Output Feedback
64
 * The designated CALG block cipher should be used in OFB (Output Feedback
65
 * Block) mode in the ISO variant, as described in <i>The Handbook of Applied
65
 * Block) mode in the ISO variant, as described in <i>The Handbook of Applied
66
 * Cryptography</i>, algorithm 7.20.</p>
66
 * Cryptography</i>, algorithm 7.20.
67
 *
67
 * <p>
68
 * <p>Let <code>k</code> be the block size of the chosen symmetric key block
68
 * Let <code>k</code> be the block size of the chosen symmetric key block
69
 * cipher algorithm; e.g. for AES this is <code>128</code> bits or <code>16</code>
69
 * cipher algorithm; e.g. for AES this is <code>128</code> bits or
70
 * octets.  The OFB mode used shall be of length/size <code>k</code>.</p>
70
 * <code>16</code> octets. The OFB mode used shall be of length/size
71
 *
71
 * <code>k</code>.
72
 * <p>It is recommended that block ciphers operating in OFB mode be used with an
72
 * <p>
73
 * It is recommended that block ciphers operating in OFB mode be used with an
73
 * Initial Vector (the mode's IV). In such a mode of operation - OFB with key
74
 * Initial Vector (the mode's IV). In such a mode of operation - OFB with key
74
 * re-use - the IV need not be secret. For the mechanism in question the IVs
75
 * re-use - the IV need not be secret. For the mechanism in question the IVs
75
 * shall be a random octet sequence of <code>k</code> bytes.</p>
76
 * shall be a random octet sequence of <code>k</code> bytes.
76
 *
77
 * <p>
77
 * The input data to the confidentiality protection algorithm shall be
78
 * The input data to the confidentiality protection algorithm shall be a
78
 * a multiple of the symmetric cipher block size <code>k</code>. When the input
79
 * multiple of the symmetric cipher block size <code>k</code>. When the input
79
 * length is not a multiple of <code>k</code> octets, the data shall be padded
80
 * length is not a multiple of <code>k</code> octets, the data shall be padded
80
 * according to the following scheme:</p>
81
 * according to the following scheme:
81
 *
82
 * <p>
82
 * <p>Assuming the length of the input is <code>l</code> octets,
83
 * Assuming the length of the input is <code>l</code> octets,
83
 * <code>(k - (l mod k))</code> octets, all having the value
84
 * <code>(k - (l mod k))</code> octets, all having the value
84
 * <code>(k - (l mod k))</code>, shall be appended to the original data. In
85
 * <code>(k - (l mod k))</code>, shall be appended to the original data. In
85
 * other words, the input is padded at the trailing end with one of the
86
 * other words, the input is padded at the trailing end with one of the
86
 * following sequences:</p>
87
 * following sequences:
87
 *
88
 * <pre>
88
 * <pre>
89
 *
89
 * 
90
 *                    01 -- if l mod k = k-1
90
 *                     01 -- if l mod k = k-1
91
 *                   02 02 -- if l mod k = k-2
91
 *                    02 02 -- if l mod k = k-2
92
 *                             ...
92
 *                              ...
93
 *                             ...
93
 *                              ...
94
 *                             ...
94
 *                              ...
95
 *                 k k ... k k -- if l mod k = 0
95
 *                  k k ... k k -- if l mod k = 0
96
 *</pre>
96
 * </pre>
97
 *
97
 * <p>
98
 * <p>The padding can be removed unambiguously since all input is padded and no
98
 * The padding can be removed unambiguously since all input is padded and no
99
 * padding sequence is a suffix of another. This padding method is well-defined
99
 * padding sequence is a suffix of another. This padding method is well-defined
100
 * if and only if <code>k &lt; 256</code> octets, which is the case with
100
 * if and only if <code>k &lt; 256</code> octets, which is the case with
101
 * symmetric key block ciphers today, and in the forseeable future.</p>
101
 * symmetric key block ciphers today, and in the forseeable future.
102
 */
102
 */
103
public final class CALG
103
public final class CALG
104
{
104
{
105
106
  // Constants and variables
107
  // --------------------------------------------------------------------------
108
109
  private Assembly assembly;
105
  private Assembly assembly;
110
111
  private Object modeNdx; // initialisation key of the cascade's attributes
106
  private Object modeNdx; // initialisation key of the cascade's attributes
112
113
  private int blockSize; // the underlying cipher's blocksize == IV length
107
  private int blockSize; // the underlying cipher's blocksize == IV length
114
115
  private int keySize; // the underlying cipher's key size (in bytes).
108
  private int keySize; // the underlying cipher's key size (in bytes).
116
109
117
  // Constructor(s)
118
  // --------------------------------------------------------------------------
119
120
  /** Private constructor to enforce instantiation through Factory method. */
110
  /** Private constructor to enforce instantiation through Factory method. */
121
  private CALG(final int blockSize, final int keySize, final Object modeNdx,
111
  private CALG(final int blockSize, final int keySize, final Object modeNdx,
122
               final Assembly assembly)
112
               final Assembly assembly)
Lines 129-140 Link Here
129
    this.assembly = assembly;
119
    this.assembly = assembly;
130
  }
120
  }
131
121
132
  // Class methods
133
  // -------------------------------------------------------------------------
134
135
  /**
122
  /**
136
   * <p>Returns an instance of a SASL-SRP CALG implementation.</p>
123
   * Returns an instance of a SASL-SRP CALG implementation.
137
   *
124
   * 
138
   * @param algorithm the name of the symmetric cipher algorithm.
125
   * @param algorithm the name of the symmetric cipher algorithm.
139
   * @return an instance of this object.
126
   * @return an instance of this object.
140
   */
127
   */
Lines 144-261 Link Here
144
    final int blockSize = cipher.defaultBlockSize();
131
    final int blockSize = cipher.defaultBlockSize();
145
    final int keySize = cipher.defaultKeySize();
132
    final int keySize = cipher.defaultKeySize();
146
    final Cascade ofbCipher = new Cascade();
133
    final Cascade ofbCipher = new Cascade();
147
    final Object modeNdx = ofbCipher.append(Stage.getInstance(
134
    IMode ofbMode = ModeFactory.getInstance(Registry.OFB_MODE,
148
                                                              ModeFactory.getInstance(
135
                                            cipher,
149
                                                                                      Registry.OFB_MODE,
136
                                            blockSize);
150
                                                                                      cipher,
137
    Stage modeStage = Stage.getInstance(ofbMode, Direction.FORWARD);
151
                                                                                      blockSize),
138
    final Object modeNdx = ofbCipher.append(modeStage);
152
                                                              Direction.FORWARD));
153
    final IPad pkcs7 = PadFactory.getInstance(Registry.PKCS7_PAD);
139
    final IPad pkcs7 = PadFactory.getInstance(Registry.PKCS7_PAD);
154
    // the passed IV may be longer that what we need. ensure correct length
155
    //      byte[] realIV = null;
156
    //      if (iv.length == blockSize) {
157
    //         realIV = iv;
158
    //      } else {
159
    //         realIV = new byte[blockSize];
160
    //         if (iv.length > blockSize) {
161
    //            System.arraycopy(iv, 0, realIV, 0, blockSize);
162
    //         } else { // shouldnt happen
163
    //            System.arraycopy(iv, 0, realIV, 0, iv.length);
164
    //         }
165
    //      }
166
167
    //      HashMap modeAttributes = new HashMap();
168
    //      modeAttributes.put(IBlockCipher.KEY_MATERIAL, K.clone());
169
    //      modeAttributes.put(IMode.IV, realIV);
170
171
    final Assembly asm = new Assembly();
140
    final Assembly asm = new Assembly();
172
    asm.addPreTransformer(Transformer.getCascadeTransformer(ofbCipher));
141
    asm.addPreTransformer(Transformer.getCascadeTransformer(ofbCipher));
173
    asm.addPreTransformer(Transformer.getPaddingTransformer(pkcs7));
142
    asm.addPreTransformer(Transformer.getPaddingTransformer(pkcs7));
174
175
    //      HashMap attributes = new HashMap();
176
    //      attributes.put(Assembly.DIRECTION, dir);
177
    //      attributes.put(modeNdx, modeAttributes);
178
    //      try {
179
    //         asm.init(attributes);
180
    //      } catch (TransformerException x) {
181
    //         throw new SaslException("getInstance()", x);
182
    //      }
183
184
    return new CALG(blockSize, keySize, modeNdx, asm);
143
    return new CALG(blockSize, keySize, modeNdx, asm);
185
  }
144
  }
186
145
187
  // Instance methods
188
  // -------------------------------------------------------------------------
189
190
  /**
146
  /**
191
   * <p>Initialises a SASL-SRP CALG implementation.</p>
147
   * Initialises a SASL-SRP CALG implementation.
192
   *
148
   * 
193
   * @param kdf the key derivation function.
149
   * @param kdf the key derivation function.
194
   * @param iv the initial vector value to use.
150
   * @param iv the initial vector value to use.
195
   * @param dir whether this CALG is used for encryption or decryption.
151
   * @param dir whether this CALG is used for encryption or decryption.
196
   */
152
   */
197
  //   public void init(byte[] K, byte[] iv, Direction dir) throws SaslException {
198
  public void init(final KDF kdf, final byte[] iv, final Direction dir)
153
  public void init(final KDF kdf, final byte[] iv, final Direction dir)
199
      throws SaslException
154
      throws SaslException
200
  {
155
  {
201
    //      IBlockCipher cipher = CipherFactory.getInstance(algorithm);
202
    //      int blockSize = cipher.defaultBlockSize();
203
    //      Cascade ofbCipher = new Cascade();
204
    //      Object modeNdx = ofbCipher.append(
205
    //            Stage.getInstace(
206
    //                  ModeFactory.getInstance(Registry.OFB_MODE, cipher, blockSize),
207
    //                  Direction.FORWARD));
208
    //      IPad pkcs7 = PadFactory.getInstance(Registry.PKCS7_PAD);
209
    // the passed IV may be longer that what we need. ensure correct length
210
    final byte[] realIV;
156
    final byte[] realIV;
211
    if (iv.length == blockSize)
157
    if (iv.length == blockSize)
212
      {
158
      realIV = iv;
213
        realIV = iv;
214
      }
215
    else
159
    else
216
      {
160
      {
217
        realIV = new byte[blockSize];
161
        realIV = new byte[blockSize];
218
        if (iv.length > blockSize)
162
        if (iv.length > blockSize)
219
          {
163
          System.arraycopy(iv, 0, realIV, 0, blockSize);
220
            System.arraycopy(iv, 0, realIV, 0, blockSize);
164
        else // shouldnt happen
221
          }
165
          System.arraycopy(iv, 0, realIV, 0, iv.length);
222
        else
223
          { // shouldnt happen
224
            System.arraycopy(iv, 0, realIV, 0, iv.length);
225
          }
226
      }
166
      }
227
228
    final HashMap modeAttributes = new HashMap();
167
    final HashMap modeAttributes = new HashMap();
229
    //      modeAttributes.put(IBlockCipher.KEY_MATERIAL, K.clone());
230
    final byte[] sk = kdf.derive(keySize);
168
    final byte[] sk = kdf.derive(keySize);
231
    modeAttributes.put(IBlockCipher.KEY_MATERIAL, sk);
169
    modeAttributes.put(IBlockCipher.KEY_MATERIAL, sk);
232
    //System.out.println("**** Initialised CALG with: "+gnu.crypto.util.Util.dumpString(sk));
233
    modeAttributes.put(IMode.IV, realIV);
170
    modeAttributes.put(IMode.IV, realIV);
234
235
    //      Assembly asm = new Assembly();
236
    //      asm.addPreTransformer(Transformer.getCascadeTransformer(ofbCipher));
237
    //      asm.addPreTransformer(Transformer.getPaddingTransformer(pkcs7));
238
239
    final HashMap attributes = new HashMap();
171
    final HashMap attributes = new HashMap();
240
    attributes.put(Assembly.DIRECTION, dir);
172
    attributes.put(Assembly.DIRECTION, dir);
241
    attributes.put(modeNdx, modeAttributes);
173
    attributes.put(modeNdx, modeAttributes);
242
    try
174
    try
243
      {
175
      {
244
        //         asm.init(attributes);
245
        assembly.init(attributes);
176
        assembly.init(attributes);
246
      }
177
      }
247
    catch (TransformerException x)
178
    catch (TransformerException x)
248
      {
179
      {
249
        throw new SaslException("getInstance()", x);
180
        throw new SaslException("getInstance()", x);
250
      }
181
      }
251
252
    //      return new CALG(asm);
253
  }
182
  }
254
183
255
  /**
184
  /**
256
   * <p>Encrypts or decrypts, depending on the mode already set, a designated
185
   * Encrypts or decrypts, depending on the mode already set, a designated array
257
   * array of bytes and returns the result.</p>
186
   * of bytes and returns the result.
258
   *
187
   * 
259
   * @param data the data to encrypt/decrypt.
188
   * @param data the data to encrypt/decrypt.
260
   * @return the decrypted/encrypted result.
189
   * @return the decrypted/encrypted result.
261
   * @throws ConfidentialityException if an exception occurs duirng the process.
190
   * @throws ConfidentialityException if an exception occurs duirng the process.
Lines 266-274 Link Here
266
  }
195
  }
267
196
268
  /**
197
  /**
269
   * <p>Encrypts or decrypts, depending on the mode already set, a designated
198
   * Encrypts or decrypts, depending on the mode already set, a designated array
270
   * array of bytes and returns the result.</p>
199
   * of bytes and returns the result.
271
   *
200
   * 
272
   * @param data the data to encrypt/decrypt.
201
   * @param data the data to encrypt/decrypt.
273
   * @param offset where to start in <code>data</code>.
202
   * @param offset where to start in <code>data</code>.
274
   * @param length how many bytes to consider in <code>data</code>.
203
   * @param length how many bytes to consider in <code>data</code>.
Lines 289-292 Link Here
289
      }
218
      }
290
    return result;
219
    return result;
291
  }
220
  }
292
}
221
}
(-)srp/ClientStore.java (-42 / +24 lines)
Lines 41-69 Link Here
41
import java.util.HashMap;
41
import java.util.HashMap;
42
42
43
/**
43
/**
44
 * <p>The client-side implementation of the SRP security context store.</p>
44
 * The client-side implementation of the SRP security context store.
45
 */
45
 */
46
public class ClientStore
46
public class ClientStore
47
{
47
{
48
49
  // Constants and variables
50
  // -------------------------------------------------------------------------
51
52
  /** The underlying singleton. */
48
  /** The underlying singleton. */
53
  private static ClientStore singleton = null;
49
  private static ClientStore singleton = null;
54
55
  /** The map of uid --> SASL Security Context record. */
50
  /** The map of uid --> SASL Security Context record. */
56
  private static final HashMap uid2ssc = new HashMap();
51
  private static final HashMap uid2ssc = new HashMap();
57
58
  /** The map of sid --> Session timing record. */
52
  /** The map of sid --> Session timing record. */
59
  private static final HashMap uid2ttl = new HashMap();
53
  private static final HashMap uid2ttl = new HashMap();
60
61
  /** A synchronisation lock. */
54
  /** A synchronisation lock. */
62
  private static final Object lock = new Object();
55
  private static final Object lock = new Object();
63
56
64
  // Constructor(s)
65
  // -------------------------------------------------------------------------
66
67
  /** Private constructor to enforce Singleton pattern. */
57
  /** Private constructor to enforce Singleton pattern. */
68
  private ClientStore()
58
  private ClientStore()
69
  {
59
  {
Lines 72-104 Link Here
72
    // TODO: add a cleaning timer thread
62
    // TODO: add a cleaning timer thread
73
  }
63
  }
74
64
75
  // Class methods
76
  // -------------------------------------------------------------------------
77
78
  /**
65
  /**
79
   * <p>Returns the classloader Singleton.</p>
66
   * Returns the classloader Singleton.
80
   *
67
   * 
81
   * @return the classloader Singleton instance.
68
   * @return the classloader Singleton instance.
82
   */
69
   */
83
  static synchronized final ClientStore instance()
70
  static synchronized final ClientStore instance()
84
  {
71
  {
85
    if (singleton == null)
72
    if (singleton == null)
86
      {
73
      singleton = new ClientStore();
87
        singleton = new ClientStore();
88
      }
89
    return singleton;
74
    return singleton;
90
  }
75
  }
91
76
92
  // Instance methods
93
  // -------------------------------------------------------------------------
94
95
  /**
77
  /**
96
   * <p>Returns a boolean flag indicating if the designated client's session is
78
   * Returns a boolean flag indicating if the designated client's session is
97
   * still alive or not.</p>
79
   * still alive or not.
98
   *
80
   * 
99
   * @param uid the identifier of the client whose session to check.
81
   * @param uid the identifier of the client whose session to check.
100
   * @return <code>true</code> if the designated client's session is still
82
   * @return <code>true</code> if the designated client's session is still
101
   * alive. <code>false</code> otherwise.
83
   *         alive. <code>false</code> otherwise.
102
   */
84
   */
103
  boolean isAlive(final String uid)
85
  boolean isAlive(final String uid)
104
  {
86
  {
Lines 107-117 Link Here
107
      {
89
      {
108
        final Object obj = uid2ssc.get(uid);
90
        final Object obj = uid2ssc.get(uid);
109
        result = (obj != null);
91
        result = (obj != null);
110
        if (result)
92
        if (result) // is it still alive?
111
          { // is it still alive?
93
          {
112
            final StoreEntry sto = (StoreEntry) uid2ttl.get(uid);
94
            final StoreEntry sto = (StoreEntry) uid2ttl.get(uid);
113
            if (!sto.isAlive())
95
            if (! sto.isAlive()) // invalidate it
114
              { // invalidate it
96
              {
115
                uid2ssc.remove(uid);
97
                uid2ssc.remove(uid);
116
                uid2ttl.remove(uid);
98
                uid2ttl.remove(uid);
117
              }
99
              }
Lines 121-131 Link Here
121
  }
103
  }
122
104
123
  /**
105
  /**
124
   * <p>Records a mapping between a client's unique identifier and its security
106
   * Records a mapping between a client's unique identifier and its security
125
   * context.</p>
107
   * context.
126
   *
108
   * 
127
   * @param uid the unique identifier of the SRP client for which the session
109
   * @param uid the unique identifier of the SRP client for which the session is
128
   * is to be cached.
110
   *          to be cached.
129
   * @param ttl the session's Time-To-Live indicator (in seconds).
111
   * @param ttl the session's Time-To-Live indicator (in seconds).
130
   * @param ctx the client's security context.
112
   * @param ctx the client's security context.
131
   */
113
   */
Lines 139-147 Link Here
139
  }
121
  }
140
122
141
  /**
123
  /**
142
   * <p>Removes the mapping between the designated SRP client unique identifier
124
   * Removes the mapping between the designated SRP client unique identifier and
143
   * and the its session security context (and other timing information).</p>
125
   * the its session security context (and other timing information).
144
   *
126
   * 
145
   * @param uid the identifier of the client whose session is to invalidate.
127
   * @param uid the identifier of the client whose session is to invalidate.
146
   */
128
   */
147
  void invalidateSession(final String uid)
129
  void invalidateSession(final String uid)
Lines 154-162 Link Here
154
  }
136
  }
155
137
156
  /**
138
  /**
157
   * <p>Returns an SRP client's security context record mapped by that client's
139
   * Returns an SRP client's security context record mapped by that client's
158
   * unique identifier.</p>
140
   * unique identifier.
159
   *
141
   * 
160
   * @param uid the identifier of the client whose session is to restore.
142
   * @param uid the identifier of the client whose session is to restore.
161
   * @return the SRP client's security context.
143
   * @return the SRP client's security context.
162
   */
144
   */
Lines 170-173 Link Here
170
      }
152
      }
171
    return result;
153
    return result;
172
  }
154
  }
173
}
155
}
(-)srp/IALG.java (-39 / +10 lines)
Lines 48-67 Link Here
48
import javax.security.sasl.SaslException;
48
import javax.security.sasl.SaslException;
49
49
50
/**
50
/**
51
 * <p>A Factory class that returns IALG (Integrity Algorithm) instances that
51
 * A Factory class that returns IALG (Integrity Algorithm) instances that
52
 * operate as described in the draft-burdis-cat-sasl-srp-04 and later.</p>
52
 * operate as described in the draft-burdis-cat-sasl-srp-04 and later.
53
 */
53
 */
54
public final class IALG implements Cloneable
54
public final class IALG
55
    implements Cloneable
55
{
56
{
56
57
  // Constants and variables
58
  // --------------------------------------------------------------------------
59
60
  private IMac hmac;
57
  private IMac hmac;
61
58
62
  // Constructor(s)
63
  // --------------------------------------------------------------------------
64
65
  /** Private constructor to enforce instantiation through Factory method. */
59
  /** Private constructor to enforce instantiation through Factory method. */
66
  private IALG(final IMac hmac)
60
  private IALG(final IMac hmac)
67
  {
61
  {
Lines 70-81 Link Here
70
    this.hmac = hmac;
64
    this.hmac = hmac;
71
  }
65
  }
72
66
73
  // Class methods
74
  // -------------------------------------------------------------------------
75
76
  /**
67
  /**
77
   * <p>Returns an instance of a SASL-SRP IALG implementation.</p>
68
   * Returns an instance of a SASL-SRP IALG implementation.
78
   *
69
   * 
79
   * @param algorithm the name of the HMAC algorithm.
70
   * @param algorithm the name of the HMAC algorithm.
80
   * @return an instance of this object.
71
   * @return an instance of this object.
81
   */
72
   */
Lines 85-128 Link Here
85
    final IMac hmac;
76
    final IMac hmac;
86
    hmac = MacFactory.getInstance(algorithm);
77
    hmac = MacFactory.getInstance(algorithm);
87
    if (hmac == null)
78
    if (hmac == null)
88
      {
79
      throw new SaslException("getInstance()",
89
        throw new SaslException("getInstance()",
80
                              new NoSuchAlgorithmException(algorithm));
90
                                new NoSuchAlgorithmException(algorithm));
91
      }
92
    // 	   try {
93
    //         byte[] sk = (byte[]) K.clone();
94
    //         HashMap map = new HashMap();
95
    //         map.put(IMac.MAC_KEY_MATERIAL, sk);
96
    //         hmac.init(map);
97
    // 	   } catch (InvalidKeyException x) {
98
    //   	   throw new SaslException("getInstance()", x);
99
    // 	   }
100
    return new IALG(hmac);
81
    return new IALG(hmac);
101
  }
82
  }
102
83
103
  // Instance methods
104
  // -------------------------------------------------------------------------
105
106
  // Cloneable interface implementation --------------------------------------
107
108
  public Object clone() throws CloneNotSupportedException
84
  public Object clone() throws CloneNotSupportedException
109
  {
85
  {
110
    return new IALG((IMac) hmac.clone());
86
    return new IALG((IMac) hmac.clone());
111
  }
87
  }
112
88
113
  // other methdds -----------------------------------------------------------
114
115
  //   public void init(final byte[] K) throws SaslException {
116
  public void init(final KDF kdf) throws SaslException
89
  public void init(final KDF kdf) throws SaslException
117
  {
90
  {
118
    try
91
    try
119
      {
92
      {
120
        //         final byte[] sk = (byte[]) K.clone();
121
        final byte[] sk = kdf.derive(hmac.macSize());
93
        final byte[] sk = kdf.derive(hmac.macSize());
122
        final HashMap map = new HashMap();
94
        final HashMap map = new HashMap();
123
        map.put(IMac.MAC_KEY_MATERIAL, sk);
95
        map.put(IMac.MAC_KEY_MATERIAL, sk);
124
        hmac.init(map);
96
        hmac.init(map);
125
        //System.out.println("**** Initialised IALG with: "+gnu.crypto.util.Util.dumpString(sk));
126
      }
97
      }
127
    catch (InvalidKeyException x)
98
    catch (InvalidKeyException x)
128
      {
99
      {
Lines 146-153 Link Here
146
  }
117
  }
147
118
148
  /**
119
  /**
149
   * <p>Returns the length (in bytes) of this SASL SRP Integrity Algorithm.</p>
120
   * Returns the length (in bytes) of this SASL SRP Integrity Algorithm.
150
   *
121
   * 
151
   * @return the length, in bytes, of this integrity protection algorithm.
122
   * @return the length, in bytes, of this integrity protection algorithm.
152
   */
123
   */
153
  public int length()
124
  public int length()
(-)srp/KDF.java (-47 / +18 lines)
Lines 47-91 Link Here
47
import java.util.HashMap;
47
import java.util.HashMap;
48
48
49
/**
49
/**
50
 * <p>The SASL-SRP KDF implementation, which is also used, depending on how it
50
 * The SASL-SRP KDF implementation, which is also used, depending on how it was
51
 * was instantiated, as a secure Pseudo Random Number Generator.</p>
51
 * instantiated, as a secure Pseudo Random Number Generator.
52
 */
52
 */
53
public class KDF
53
public class KDF
54
{
54
{
55
55
  private static final int AES_BLOCK_SIZE = 16; // default block size for AES
56
  // Constants and variables
57
  // -------------------------------------------------------------------------
58
59
  private static final int AES_BLOCK_SIZE = 16; // default block size for the AES
60
61
  private static final int AES_KEY_SIZE = 16; // default key size for the AES
56
  private static final int AES_KEY_SIZE = 16; // default key size for the AES
62
63
  private static final byte[] buffer = new byte[1];
57
  private static final byte[] buffer = new byte[1];
64
65
  /** Our default source of randomness. */
58
  /** Our default source of randomness. */
66
  private static final PRNG prng = PRNG.getInstance();
59
  private static final PRNG prng = PRNG.getInstance();
67
68
  /** The shared secret K to use. */
69
  //   private byte[] keyMaterial;
70
  /** The underlying UMAC Generator instance. */
60
  /** The underlying UMAC Generator instance. */
71
  private UMacGenerator umac = null;
61
  private UMacGenerator umac = null;
72
62
73
  // Constructor(s)
74
  // -------------------------------------------------------------------------
75
76
  /**
63
  /**
77
   * <p>Constructs an instance of the <code>KDF</code> initialised with the
64
   * Constructs an instance of the <code>KDF</code> initialised with the
78
   * designated shared secret bytes.</p>
65
   * designated shared secret bytes.
79
   *
66
   * 
80
   * @param keyMaterial the SASL SRP shared secret (K) bytes.
67
   * @param keyMaterial the SASL SRP shared secret (K) bytes.
81
   */
68
   */
82
  private KDF(final byte[] keyMaterial, final int ndx)
69
  private KDF(final byte[] keyMaterial, final int ndx)
83
  {
70
  {
84
    super();
71
    super();
85
72
86
    //      if (ndx != 0) {
87
    //         this.keyMaterial = (byte[]) keyMaterial.clone();
88
    //      }
89
    final HashMap map = new HashMap();
73
    final HashMap map = new HashMap();
90
    map.put(UMacGenerator.CIPHER, Registry.AES_CIPHER);
74
    map.put(UMacGenerator.CIPHER, Registry.AES_CIPHER);
91
    map.put(UMacGenerator.INDEX, Integer.valueOf(ndx));
75
    map.put(UMacGenerator.INDEX, Integer.valueOf(ndx));
Lines 93-113 Link Here
93
    final byte[] key = new byte[AES_KEY_SIZE];
77
    final byte[] key = new byte[AES_KEY_SIZE];
94
    System.arraycopy(keyMaterial, 0, key, 0, AES_KEY_SIZE);
78
    System.arraycopy(keyMaterial, 0, key, 0, AES_KEY_SIZE);
95
    map.put(IBlockCipher.KEY_MATERIAL, key);
79
    map.put(IBlockCipher.KEY_MATERIAL, key);
96
97
    umac = new UMacGenerator();
80
    umac = new UMacGenerator();
98
    umac.init(map);
81
    umac.init(map);
99
    //System.out.println("**** Initialised KDF with: "+gnu.crypto.util.Util.dumpString(key));
100
  }
82
  }
101
83
102
  // Class methods
103
  // -------------------------------------------------------------------------
104
105
  /**
84
  /**
106
   * <p>A Factory mehod that returns an instance of a <code>KDF</code> based on
85
   * A Factory mehod that returns an instance of a <code>KDF</code> based on
107
   * supplied seed data.</p>
86
   * supplied seed data.
108
   *
87
   * 
109
   * @param K the SASL SRP shared secret for a <code>KDF</code> to be used for
88
   * @param K the SASL SRP shared secret for a <code>KDF</code> to be used for
110
   * <i>CALG</i> and <i>IALG</i> setup. <code>null</code> otherwise.
89
   *          <i>CALG</i> and <i>IALG</i> setup. <code>null</code> otherwise.
111
   * @return an instance of a <code>KDF</code>.
90
   * @return an instance of a <code>KDF</code>.
112
   */
91
   */
113
  static final KDF getInstance(final byte[] K)
92
  static final KDF getInstance(final byte[] K)
Lines 134-169 Link Here
134
    return (buffer[0] & 0xFF);
113
    return (buffer[0] & 0xFF);
135
  }
114
  }
136
115
137
  // Instance methods
138
  // -------------------------------------------------------------------------
139
140
  /**
116
  /**
141
   * <p>Returns a designated number of bytes suitable for use in the SASL SRP
117
   * Returns a designated number of bytes suitable for use in the SASL SRP
142
   * mechanism.</p>
118
   * mechanism.
143
   *
119
   * 
144
   * @param length the number of bytes needed.
120
   * @param length the number of bytes needed.
145
   * @return a byte array containing the generated/selected bytes.
121
   * @return a byte array containing the generated/selected bytes.
146
   */
122
   */
147
  public synchronized byte[] derive(final int length)
123
  public synchronized byte[] derive(final int length)
148
  {
124
  {
149
    final byte[] result = new byte[length];
125
    final byte[] result = new byte[length];
150
    //      if (keyMaterial == null || length > keyMaterial.length) {
151
    try
126
    try
152
      {
127
      {
153
        umac.nextBytes(result, 0, length);
128
        umac.nextBytes(result, 0, length);
154
      }
129
      }
155
    catch (IllegalStateException x)
130
    catch (IllegalStateException x) // should not happen
156
      { // should not happen
131
      {
157
        x.printStackTrace(System.err);
132
        x.printStackTrace(System.err);
158
      }
133
      }
159
    catch (LimitReachedException x)
134
    catch (LimitReachedException x) // idem
160
      { // idem
135
      {
161
        x.printStackTrace(System.err);
136
        x.printStackTrace(System.err);
162
      }
137
      }
163
    //      } else {
164
    //         System.arraycopy(keyMaterial, 0, result, 0, length);
165
    //      }
166
167
    return result;
138
    return result;
168
  }
139
  }
169
}
140
}
(-)srp/PasswordFile.java (-189 / +116 lines)
Lines 61-130 Link Here
61
import java.util.StringTokenizer;
61
import java.util.StringTokenizer;
62
62
63
/**
63
/**
64
 * <p>The implementation of SRP password files.</p>
64
 * The implementation of SRP password files.
65
 *
65
 * <p>
66
 * <p>For SRP, there are three (3) files:
66
 * For SRP, there are three (3) files:
67
 * <ol>
67
 * <ol>
68
 *    <li>The password configuration file: tpasswd.conf. It contains the pairs
68
 * <li>The password configuration file: tpasswd.conf. It contains the pairs
69
 *    &lt;N,g> indexed by a number for each pair used for a user. By default,
69
 * &lt;N,g> indexed by a number for each pair used for a user. By default, this
70
 *    this file's pathname is constructed from the base password file pathname
70
 * file's pathname is constructed from the base password file pathname by
71
 *    by prepending it with the ".conf" suffix.</li>
71
 * prepending it with the ".conf" suffix.</li>
72
 *
72
 * <li>The base password file: tpasswd. It contains the related password
73
 *    <li>The base password file: tpasswd. It contains the related password
73
 * entries for all the users with values computed using SRP's default message
74
 *    entries for all the users with values computed using SRP's default
74
 * digest algorithm: SHA-1 (with 160-bit output block size).</li>
75
 *    message digest algorithm: SHA-1 (with 160-bit output block size).</li>
75
 * <li>The extended password file: tpasswd2. Its name, by default, is
76
 *
76
 * constructed by adding the suffix "2" to the fully qualified pathname of the
77
 *    <li>The extended password file: tpasswd2. Its name, by default, is
77
 * base password file. It contains, in addition to the same fields as the base
78
 *    constructed by adding the suffix "2" to the fully qualified pathname of
78
 * password file, albeit with a different verifier value, an extra field
79
 *    the base password file. It contains, in addition to the same fields as
79
 * identifying the message digest algorithm used to compute this (verifier)
80
 *    the base password file, albeit with a different verifier value, an extra
80
 * value.</li>
81
 *    field identifying the message digest algorithm used to compute this
81
 * </ol>
82
 *    (verifier) value.</li>
82
 * <p>
83
 * </ol></p>
83
 * This implementation assumes the following message digest algorithm codes:
84
 *
85
 * <p>This implementation assumes the following message digest algorithm codes:
86
 * <ul>
84
 * <ul>
87
 *    <li>0: the default hash algorithm, which is SHA-1 (or its alias SHA-160).</li>
85
 * <li>0: the default hash algorithm, which is SHA-1 (or its alias SHA-160).</li>
88
 *    <li>1: MD5.</li>
86
 * <li>1: MD5.</li>
89
 *    <li>2: RIPEMD-128.</li>
87
 * <li>2: RIPEMD-128.</li>
90
 *    <li>3: RIPEMD-160.</li>
88
 * <li>3: RIPEMD-160.</li>
91
 *    <li>4: SHA-256.</li>
89
 * <li>4: SHA-256.</li>
92
 *    <li>5: SHA-384.</li>
90
 * <li>5: SHA-384.</li>
93
 *    <li>6: SHA-512.</li>
91
 * <li>6: SHA-512.</li>
94
 * </ul></p>
92
 * </ul>
95
 *
93
 * <p>
96
 * <p><b>IMPORTANT:</b> This method computes the verifiers as described in
94
 * <b>IMPORTANT:</b> This method computes the verifiers as described in
97
 * RFC-2945, which differs from the description given on the web page for
95
 * RFC-2945, which differs from the description given on the web page for SRP-6.
98
 * SRP-6.</p>
96
 * <p>
99
 *
97
 * Reference:
100
 * <p>Reference:</p>
101
 * <ol>
98
 * <ol>
102
 *    <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
99
 * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
103
 *    Thomas J. Wu.</li>
100
 * Thomas J. Wu.</li>
104
 * </ol>
101
 * </ol>
105
 */
102
 */
106
public class PasswordFile
103
public class PasswordFile
107
{
104
{
108
109
  // Constants and variables
110
  // -------------------------------------------------------------------------
111
112
  // names of property keys used in this class
105
  // names of property keys used in this class
113
  private static final String USER_FIELD = "user";
106
  private static final String USER_FIELD = "user";
114
115
  private static final String VERIFIERS_FIELD = "verifier";
107
  private static final String VERIFIERS_FIELD = "verifier";
116
117
  private static final String SALT_FIELD = "salt";
108
  private static final String SALT_FIELD = "salt";
118
119
  private static final String CONFIG_FIELD = "config";
109
  private static final String CONFIG_FIELD = "config";
120
121
  private static String DEFAULT_FILE;
110
  private static String DEFAULT_FILE;
122
  static
111
  static
123
    {
112
    {
124
      DEFAULT_FILE = System.getProperty(SRPRegistry.PASSWORD_FILE,
113
      DEFAULT_FILE = System.getProperty(SRPRegistry.PASSWORD_FILE,
125
                                        SRPRegistry.DEFAULT_PASSWORD_FILE);
114
                                        SRPRegistry.DEFAULT_PASSWORD_FILE);
126
    }
115
    }
127
128
  /** The SRP algorithm instances used by this object. */
116
  /** The SRP algorithm instances used by this object. */
129
  private static final HashMap srps;
117
  private static final HashMap srps;
130
  static
118
  static
Lines 149-175 Link Here
149
    }
137
    }
150
138
151
  private String confName, pwName, pw2Name;
139
  private String confName, pwName, pw2Name;
152
153
  private File configFile, passwdFile, passwd2File;
140
  private File configFile, passwdFile, passwd2File;
154
155
  private long lastmodPasswdFile, lastmodPasswd2File;
141
  private long lastmodPasswdFile, lastmodPasswd2File;
156
157
  private HashMap entries = new HashMap();
142
  private HashMap entries = new HashMap();
158
159
  private HashMap configurations = new HashMap();
143
  private HashMap configurations = new HashMap();
160
161
  // default N values to use when creating a new password.conf file
144
  // default N values to use when creating a new password.conf file
162
  private static final BigInteger[] Nsrp = new BigInteger[] {
145
  private static final BigInteger[] Nsrp = new BigInteger[] {
163
                                                             SRPAlgorithm.N_2048,
146
      SRPAlgorithm.N_2048,
164
                                                             SRPAlgorithm.N_1536,
147
      SRPAlgorithm.N_1536,
165
                                                             SRPAlgorithm.N_1280,
148
      SRPAlgorithm.N_1280,
166
                                                             SRPAlgorithm.N_1024,
149
      SRPAlgorithm.N_1024,
167
                                                             SRPAlgorithm.N_768,
150
      SRPAlgorithm.N_768,
168
                                                             SRPAlgorithm.N_640,
151
      SRPAlgorithm.N_640,
169
                                                             SRPAlgorithm.N_512 };
152
      SRPAlgorithm.N_512 };
170
171
  // Constructor(s)
172
  // -------------------------------------------------------------------------
173
153
174
  public PasswordFile() throws IOException
154
  public PasswordFile() throws IOException
175
  {
155
  {
Lines 205-267 Link Here
205
    update();
185
    update();
206
  }
186
  }
207
187
208
  // Class methods
209
  // -------------------------------------------------------------------------
210
211
  /**
188
  /**
212
   * <p>Returns a string representing the decimal value of an integer
189
   * Returns a string representing the decimal value of an integer identifying
213
   * identifying the message digest algorithm to use for the SRP computations.
190
   * the message digest algorithm to use for the SRP computations.
214
   * </p>
191
   * 
215
   *
216
   * @param mdName the canonical name of a message digest algorithm.
192
   * @param mdName the canonical name of a message digest algorithm.
217
   * @return a string representing the decimal value of an ID for that
193
   * @return a string representing the decimal value of an ID for that
218
   * algorithm.
194
   *         algorithm.
219
   */
195
   */
220
  private static final String nameToID(final String mdName)
196
  private static final String nameToID(final String mdName)
221
  {
197
  {
222
    if (Registry.SHA_HASH.equalsIgnoreCase(mdName)
198
    if (Registry.SHA_HASH.equalsIgnoreCase(mdName)
223
        || Registry.SHA1_HASH.equalsIgnoreCase(mdName)
199
        || Registry.SHA1_HASH.equalsIgnoreCase(mdName)
224
        || Registry.SHA160_HASH.equalsIgnoreCase(mdName))
200
        || Registry.SHA160_HASH.equalsIgnoreCase(mdName))
225
      {
201
      return "0";
226
        return "0";
227
      }
228
    else if (Registry.MD5_HASH.equalsIgnoreCase(mdName))
202
    else if (Registry.MD5_HASH.equalsIgnoreCase(mdName))
229
      {
203
      return "1";
230
        return "1";
231
      }
232
    else if (Registry.RIPEMD128_HASH.equalsIgnoreCase(mdName))
204
    else if (Registry.RIPEMD128_HASH.equalsIgnoreCase(mdName))
233
      {
205
      return "2";
234
        return "2";
235
      }
236
    else if (Registry.RIPEMD160_HASH.equalsIgnoreCase(mdName))
206
    else if (Registry.RIPEMD160_HASH.equalsIgnoreCase(mdName))
237
      {
207
      return "3";
238
        return "3";
239
      }
240
    else if (Registry.SHA256_HASH.equalsIgnoreCase(mdName))
208
    else if (Registry.SHA256_HASH.equalsIgnoreCase(mdName))
241
      {
209
      return "4";
242
        return "4";
243
      }
244
    else if (Registry.SHA384_HASH.equalsIgnoreCase(mdName))
210
    else if (Registry.SHA384_HASH.equalsIgnoreCase(mdName))
245
      {
211
      return "5";
246
        return "5";
247
      }
248
    else if (Registry.SHA512_HASH.equalsIgnoreCase(mdName))
212
    else if (Registry.SHA512_HASH.equalsIgnoreCase(mdName))
249
      {
213
      return "6";
250
        return "6";
251
      }
252
    return "0";
214
    return "0";
253
  }
215
  }
254
216
255
  // SRP password configuration file methods ---------------------------------
256
257
  /**
217
  /**
258
   * <p>Checks if the current configuration file contains the &lt;N, g> pair
218
   * Checks if the current configuration file contains the &lt;N, g> pair for
259
   * for the designated <code>index</code>.</p>
219
   * the designated <code>index</code>.
260
   *
220
   * 
261
   * @param index a string representing 1-digit identification of an &lt;N, g>
221
   * @param index a string representing 1-digit identification of an &lt;N, g>
262
   * pair used.
222
   *          pair used.
263
   * @return <code>true</code> if the designated <code>index</code> is that of
223
   * @return <code>true</code> if the designated <code>index</code> is that
264
   * a known &lt;N, g> pair, and <code>false</code> otherwise.
224
   *         of a known &lt;N, g> pair, and <code>false</code> otherwise.
265
   * @throws IOException if an exception occurs during the process.
225
   * @throws IOException if an exception occurs during the process.
266
   * @see SRPRegistry#N_2048_BITS
226
   * @see SRPRegistry#N_2048_BITS
267
   * @see SRPRegistry#N_1536_BITS
227
   * @see SRPRegistry#N_1536_BITS
Lines 279-294 Link Here
279
  }
239
  }
280
240
281
  /**
241
  /**
282
   * <p>Returns a pair of strings representing the pair of <code>N</code> and
242
   * Returns a pair of strings representing the pair of <code>N</code> and
283
   * <code>g</code> MPIs for the designated <code>index</code>.</p>
243
   * <code>g</code> MPIs for the designated <code>index</code>.
284
   *
244
   * 
285
   * @param index a string representing 1-digit identification of an &lt;N, g>
245
   * @param index a string representing 1-digit identification of an &lt;N, g>
286
   * pair to look up.
246
   *          pair to look up.
287
   * @return a pair of strings, arranged in an array, where the first (at index
247
   * @return a pair of strings, arranged in an array, where the first (at index
288
   * position #0) is the repesentation of the MPI <code>N</code>, and the
248
   *         position #0) is the repesentation of the MPI <code>N</code>, and
289
   * second (at index position #1) is the representation of the MPI
249
   *         the second (at index position #1) is the representation of the MPI
290
   * <code>g</code>. If the <code>index</code> refers to an unknown pair, then
250
   *         <code>g</code>. If the <code>index</code> refers to an unknown
291
   * an empty string array is returned.
251
   *         pair, then an empty string array is returned.
292
   * @throws IOException if an exception occurs during the process.
252
   * @throws IOException if an exception occurs during the process.
293
   */
253
   */
294
  public synchronized String[] lookupConfig(final String index)
254
  public synchronized String[] lookupConfig(final String index)
Lines 297-310 Link Here
297
    checkCurrent();
257
    checkCurrent();
298
    String[] result = null;
258
    String[] result = null;
299
    if (configurations.containsKey(index))
259
    if (configurations.containsKey(index))
300
      {
260
      result = (String[]) configurations.get(index);
301
        result = (String[]) configurations.get(index);
302
      }
303
    return result;
261
    return result;
304
  }
262
  }
305
263
306
  // SRP base and extended password configuration files methods --------------
307
308
  public synchronized boolean contains(final String user) throws IOException
264
  public synchronized boolean contains(final String user) throws IOException
309
  {
265
  {
310
    checkCurrent();
266
    checkCurrent();
Lines 317-325 Link Here
317
  {
273
  {
318
    checkCurrent();
274
    checkCurrent();
319
    if (entries.containsKey(user))
275
    if (entries.containsKey(user))
320
      {
276
      throw new UserAlreadyExistsException(user);
321
        throw new UserAlreadyExistsException(user);
322
      }
323
    final HashMap fields = new HashMap(4);
277
    final HashMap fields = new HashMap(4);
324
    fields.put(USER_FIELD, user); // 0
278
    fields.put(USER_FIELD, user); // 0
325
    fields.put(VERIFIERS_FIELD, newVerifiers(user, salt, passwd, index)); // 1
279
    fields.put(VERIFIERS_FIELD, newVerifiers(user, salt, passwd, index)); // 1
Lines 333-342 Link Here
333
      throws IOException
287
      throws IOException
334
  {
288
  {
335
    checkCurrent();
289
    checkCurrent();
336
    if (!entries.containsKey(user))
290
    if (! entries.containsKey(user))
337
      {
291
      throw new NoSuchUserException(user);
338
        throw new NoSuchUserException(user);
339
      }
340
    final HashMap fields = (HashMap) entries.get(user);
292
    final HashMap fields = (HashMap) entries.get(user);
341
    final byte[] salt;
293
    final byte[] salt;
342
    try
294
    try
Lines 368-394 Link Here
368
    finally
320
    finally
369
      {
321
      {
370
        if (pw1 != null)
322
        if (pw1 != null)
371
          {
323
          try
372
            try
324
            {
373
              {
325
              pw1.flush();
374
                pw1.flush();
326
            }
375
              }
327
          finally
376
            finally
328
            {
377
              {
329
              pw1.close();
378
                pw1.close();
330
            }
379
              }
380
          }
381
        if (pw2 != null)
331
        if (pw2 != null)
382
          {
332
          try
383
            try
333
            {
384
              {
334
              pw2.flush();
385
                pw2.flush();
335
            }
386
              }
336
          finally
387
            finally
337
            {
388
              {
338
              pw2.close();
389
                pw2.close();
339
            }
390
              }
391
          }
392
        try
340
        try
393
          {
341
          {
394
            f1.close();
342
            f1.close();
Lines 409-432 Link Here
409
  }
357
  }
410
358
411
  /**
359
  /**
412
   * <p>Returns the triplet: verifier, salt and configuration file index, of a
360
   * Returns the triplet: verifier, salt and configuration file index, of a
413
   * designated user, and a designated message digest algorithm name, as an
361
   * designated user, and a designated message digest algorithm name, as an
414
   * array of strings.</p>
362
   * array of strings.
415
   *
363
   * 
416
   * @param user the username.
364
   * @param user the username.
417
   * @param mdName the canonical name of the SRP's message digest algorithm.
365
   * @param mdName the canonical name of the SRP's message digest algorithm.
418
   * @return a string array containing, in this order, the BASE-64 encodings of
366
   * @return a string array containing, in this order, the BASE-64 encodings of
419
   * the verifier, the salt and the index in the password configuration file of
367
   *         the verifier, the salt and the index in the password configuration
420
   * the MPIs N and g of the designated user.
368
   *         file of the MPIs N and g of the designated user.
421
   */
369
   */
422
  public synchronized String[] lookup(final String user, final String mdName)
370
  public synchronized String[] lookup(final String user, final String mdName)
423
      throws IOException
371
      throws IOException
424
  {
372
  {
425
    checkCurrent();
373
    checkCurrent();
426
    if (!entries.containsKey(user))
374
    if (! entries.containsKey(user))
427
      {
375
      throw new NoSuchUserException(user);
428
        throw new NoSuchUserException(user);
429
      }
430
    final HashMap fields = (HashMap) entries.get(user);
376
    final HashMap fields = (HashMap) entries.get(user);
431
    final HashMap verifiers = (HashMap) fields.get(VERIFIERS_FIELD);
377
    final HashMap verifiers = (HashMap) fields.get(VERIFIERS_FIELD);
432
    final String salt = (String) fields.get(SALT_FIELD);
378
    final String salt = (String) fields.get(SALT_FIELD);
Lines 435-442 Link Here
435
    return new String[] { verifier, salt, index };
381
    return new String[] { verifier, salt, index };
436
  }
382
  }
437
383
438
  // Other instance methods --------------------------------------------------
439
440
  private synchronized void readOrCreateConf() throws IOException
384
  private synchronized void readOrCreateConf() throws IOException
441
  {
385
  {
442
    configurations.clear();
386
    configurations.clear();
Lines 468-480 Link Here
468
        finally
412
        finally
469
          {
413
          {
470
            if (pw0 != null)
414
            if (pw0 != null)
471
              {
415
              pw0.close();
472
                pw0.close();
473
              }
474
            else if (f0 != null)
416
            else if (f0 != null)
475
              {
417
              f0.close();
476
                f0.close();
477
              }
478
          }
418
          }
479
      }
419
      }
480
  }
420
  }
Lines 510-535 Link Here
510
      {
450
      {
511
        ndx = (String) it.next();
451
        ndx = (String) it.next();
512
        mpi = (String[]) configurations.get(ndx);
452
        mpi = (String[]) configurations.get(ndx);
513
        sb = new StringBuffer(ndx).append(":").append(mpi[0]).append(":").append(
453
        sb = new StringBuffer(ndx)
514
                                                                                 mpi[1]);
454
            .append(":").append(mpi[0])
455
            .append(":").append(mpi[1]);
515
        pw.println(sb.toString());
456
        pw.println(sb.toString());
516
      }
457
      }
517
  }
458
  }
518
459
519
  /**
460
  /**
520
   * <p>Compute the new verifiers for the designated username and password.</p>
461
   * Compute the new verifiers for the designated username and password.
521
   *
462
   * <p>
522
   * <p><b>IMPORTANT:</b> This method computes the verifiers as described in
463
   * <b>IMPORTANT:</b> This method computes the verifiers as described in
523
   * RFC-2945, which differs from the description given on the web page for
464
   * RFC-2945, which differs from the description given on the web page for
524
   * SRP-6.</p>
465
   * SRP-6.
525
   *
466
   * 
526
   * @param user the user's name.
467
   * @param user the user's name.
527
   * @param s the user's salt.
468
   * @param s the user's salt.
528
   * @param password the user's password
469
   * @param password the user's password
529
   * @param index the index of the &lt;N, g> pair to use for this user.
470
   * @param index the index of the &lt;N, g> pair to use for this user.
530
   * @return a {@link java.util.Map} of user verifiers.
471
   * @return a {@link java.util.Map} of user verifiers.
531
   * @throws UnsupportedEncodingException if the US-ASCII decoder is not
472
   * @throws UnsupportedEncodingException if the US-ASCII decoder is not
532
   * available on this platform.
473
   *           available on this platform.
533
   */
474
   */
534
  private HashMap newVerifiers(final String user, final byte[] s,
475
  private HashMap newVerifiers(final String user, final byte[] s,
535
                               final String password, final String index)
476
                               final String password, final String index)
Lines 539-545 Link Here
539
    final String[] mpi = (String[]) configurations.get(index);
480
    final String[] mpi = (String[]) configurations.get(index);
540
    final BigInteger N = new BigInteger(1, Util.fromBase64(mpi[0]));
481
    final BigInteger N = new BigInteger(1, Util.fromBase64(mpi[0]));
541
    final BigInteger g = new BigInteger(1, Util.fromBase64(mpi[1]));
482
    final BigInteger g = new BigInteger(1, Util.fromBase64(mpi[1]));
542
543
    final HashMap result = new HashMap(srps.size());
483
    final HashMap result = new HashMap(srps.size());
544
    BigInteger x, v;
484
    BigInteger x, v;
545
    SRP srp;
485
    SRP srp;
Lines 550-556 Link Here
550
        x = new BigInteger(1, srp.computeX(s, user, password));
490
        x = new BigInteger(1, srp.computeX(s, user, password));
551
        v = g.modPow(x, N);
491
        v = g.modPow(x, N);
552
        final String verifier = Util.toBase64(v.toByteArray());
492
        final String verifier = Util.toBase64(v.toByteArray());
553
554
        result.put(digestID, verifier);
493
        result.put(digestID, verifier);
555
      }
494
      }
556
    return result;
495
    return result;
Lines 559-565 Link Here
559
  private synchronized void update() throws IOException
498
  private synchronized void update() throws IOException
560
  {
499
  {
561
    entries.clear();
500
    entries.clear();
562
563
    FileInputStream fis;
501
    FileInputStream fis;
564
    passwdFile = new File(pwName);
502
    passwdFile = new File(pwName);
565
    lastmodPasswdFile = passwdFile.lastModified();
503
    lastmodPasswdFile = passwdFile.lastModified();
Lines 587-595 Link Here
587
  {
525
  {
588
    if (passwdFile.lastModified() > lastmodPasswdFile
526
    if (passwdFile.lastModified() > lastmodPasswdFile
589
        || passwd2File.lastModified() > lastmodPasswd2File)
527
        || passwd2File.lastModified() > lastmodPasswd2File)
590
      {
528
      update();
591
        update();
592
      }
593
  }
529
  }
594
530
595
  private void readPasswd(final InputStream in) throws IOException
531
  private void readPasswd(final InputStream in) throws IOException
Lines 611-626 Link Here
611
          {
547
          {
612
            throw new IOException("SRP base password file corrupt");
548
            throw new IOException("SRP base password file corrupt");
613
          }
549
          }
614
615
        final HashMap verifiers = new HashMap(6);
550
        final HashMap verifiers = new HashMap(6);
616
        verifiers.put("0", verifier);
551
        verifiers.put("0", verifier);
617
618
        final HashMap fields = new HashMap(4);
552
        final HashMap fields = new HashMap(4);
619
        fields.put(USER_FIELD, user);
553
        fields.put(USER_FIELD, user);
620
        fields.put(VERIFIERS_FIELD, verifiers);
554
        fields.put(VERIFIERS_FIELD, verifiers);
621
        fields.put(SALT_FIELD, salt);
555
        fields.put(SALT_FIELD, salt);
622
        fields.put(CONFIG_FIELD, index);
556
        fields.put(CONFIG_FIELD, index);
623
624
        entries.put(user, fields);
557
        entries.put(user, fields);
625
      }
558
      }
626
  }
559
  }
Lines 644-650 Link Here
644
          {
577
          {
645
            throw new IOException("SRP extended password file corrupt");
578
            throw new IOException("SRP extended password file corrupt");
646
          }
579
          }
647
648
        fields = (HashMap) entries.get(user);
580
        fields = (HashMap) entries.get(user);
649
        if (fields != null)
581
        if (fields != null)
650
          {
582
          {
Lines 666-698 Link Here
666
      {
598
      {
667
        user = (String) i.next();
599
        user = (String) i.next();
668
        fields = (HashMap) entries.get(user);
600
        fields = (HashMap) entries.get(user);
669
        if (!user.equals(fields.get(USER_FIELD)))
601
        if (! user.equals(fields.get(USER_FIELD)))
670
          {
602
          throw new IOException("Inconsistent SRP password data");
671
            throw new IOException("Inconsistent SRP password data");
672
          }
673
        verifiers = (HashMap) fields.get(VERIFIERS_FIELD);
603
        verifiers = (HashMap) fields.get(VERIFIERS_FIELD);
674
        sb1 = new StringBuffer().append(user).append(":").append(
604
        sb1 = new StringBuffer(user)
675
                                                                 (String) verifiers.get("0")).append(
605
            .append(":").append((String) verifiers.get("0"))
676
                                                                                                     ":").append(
606
            .append(":").append((String) fields.get(SALT_FIELD))
677
                                                                                                                 (String) fields.get(SALT_FIELD)).append(
607
            .append(":").append((String) fields.get(CONFIG_FIELD));
678
                                                                                                                                                         ":").append(
679
                                                                                                                                                                     (String) fields.get(CONFIG_FIELD));
680
        pw1.println(sb1.toString());
608
        pw1.println(sb1.toString());
681
        // write extended information
609
        // write extended information
682
        j = verifiers.keySet().iterator();
610
        j = verifiers.keySet().iterator();
683
        while (j.hasNext())
611
        while (j.hasNext())
684
          {
612
          {
685
            digestID = (String) j.next();
613
            digestID = (String) j.next();
686
            if (!"0".equals(digestID))
614
            if (! "0".equals(digestID))
687
              {
615
              {
688
                // #0 is the default digest, already present in tpasswd!
616
                // #0 is the default digest, already present in tpasswd!
689
                sb2 = new StringBuffer().append(digestID).append(":").append(
617
                sb2 = new StringBuffer(digestID)
690
                                                                             user).append(
618
                    .append(":").append(user)
691
                                                                                          ":").append(
619
                    .append(":").append((String) verifiers.get(digestID));
692
                                                                                                      (String) verifiers.get(digestID));
693
                pw2.println(sb2.toString());
620
                pw2.println(sb2.toString());
694
              }
621
              }
695
          }
622
          }
696
      }
623
      }
697
  }
624
  }
698
}
625
}
(-)srp/SRP.java (-62 / +32 lines)
Lines 47-73 Link Here
47
import java.util.HashMap;
47
import java.util.HashMap;
48
48
49
/**
49
/**
50
 * <p>A Factory class that returns SRP Singletons that know all SRP-related
50
 * A Factory class that returns SRP Singletons that know all SRP-related
51
 * mathematical computations and protocol-related operations for both the
51
 * mathematical computations and protocol-related operations for both the
52
 * client- and server-sides.</p>
52
 * client- and server-sides.
53
 */
53
 */
54
public final class SRP
54
public final class SRP
55
{
55
{
56
57
  // Constants and variables
58
  // --------------------------------------------------------------------------
59
60
  /** The map of already instantiated SRP algorithm instances. */
56
  /** The map of already instantiated SRP algorithm instances. */
61
  private static final HashMap algorithms = new HashMap();
57
  private static final HashMap algorithms = new HashMap();
62
63
  private static final byte COLON = (byte) 0x3A;
58
  private static final byte COLON = (byte) 0x3A;
64
65
  /** The underlying message digest algorithm used for all SRP calculations. */
59
  /** The underlying message digest algorithm used for all SRP calculations. */
66
  private IMessageDigest mda;
60
  private IMessageDigest mda;
67
61
68
  // Constructor(s)
69
  // --------------------------------------------------------------------------
70
71
  /** Trivial private constructor to enforce Singleton pattern. */
62
  /** Trivial private constructor to enforce Singleton pattern. */
72
  private SRP(final IMessageDigest mda)
63
  private SRP(final IMessageDigest mda)
73
  {
64
  {
Lines 76-100 Link Here
76
    this.mda = mda;
67
    this.mda = mda;
77
  }
68
  }
78
69
79
  // Class methods
80
  // -------------------------------------------------------------------------
81
82
  /**
70
  /**
83
   * <p>Returns an instance of this object that uses the designated message
71
   * Returns an instance of this object that uses the designated message digest
84
   * digest algorithm as its digest function.</p>
72
   * algorithm as its digest function.
85
   *
73
   * 
86
   * @return an instance of this object for the designated digest name.
74
   * @return an instance of this object for the designated digest name.
87
   */
75
   */
88
  public static synchronized SRP instance(String mdName)
76
  public static synchronized SRP instance(String mdName)
89
  {
77
  {
90
    if (mdName != null)
78
    if (mdName != null)
91
      {
79
      mdName = mdName.trim().toLowerCase();
92
        mdName = mdName.trim().toLowerCase();
93
      }
94
    if (mdName == null || mdName.equals(""))
80
    if (mdName == null || mdName.equals(""))
95
      {
81
      mdName = SRPRegistry.SRP_DEFAULT_DIGEST_NAME;
96
        mdName = SRPRegistry.SRP_DEFAULT_DIGEST_NAME;
97
      }
98
    SRP result = (SRP) algorithms.get(mdName);
82
    SRP result = (SRP) algorithms.get(mdName);
99
    if (result == null)
83
    if (result == null)
100
      {
84
      {
Lines 110-140 Link Here
110
  {
94
  {
111
    final byte[] result = new byte[length];
95
    final byte[] result = new byte[length];
112
    for (int i = 0; i < length; ++i)
96
    for (int i = 0; i < length; ++i)
113
      {
97
      result[i] = (byte)(b1[i] ^ b2[i]);
114
        result[i] = (byte) (b1[i] ^ b2[i]);
115
      }
116
    return result;
98
    return result;
117
  }
99
  }
118
100
119
  // Instance methods
120
  // -------------------------------------------------------------------------
121
122
  /** @return the message digest algorithm name used by this instance. */
101
  /** @return the message digest algorithm name used by this instance. */
123
  public String getAlgorithm()
102
  public String getAlgorithm()
124
  {
103
  {
125
    return mda.name();
104
    return mda.name();
126
  }
105
  }
127
106
128
  // Message Digest algorithm related methods --------------------------------
129
130
  /**
107
  /**
131
   * <p>Returns a new instance of the SRP message digest algorithm --which is
108
   * Returns a new instance of the SRP message digest algorithm --which is
132
   * SHA-160 by default, but could be anything else provided the proper
109
   * SHA-160 by default, but could be anything else provided the proper
133
   * conditions as specified in the SRP specifications.</p>
110
   * conditions as specified in the SRP specifications.
134
   *
111
   * 
135
   * @return a new instance of the underlying SRP message digest algorithm.
112
   * @return a new instance of the underlying SRP message digest algorithm.
136
   * @throws RuntimeException if the implementation of the message digest
113
   * @throws RuntimeException if the implementation of the message digest
137
   * algorithm does not support cloning.
114
   *           algorithm does not support cloning.
138
   */
115
   */
139
  public IMessageDigest newDigest()
116
  public IMessageDigest newDigest()
140
  {
117
  {
Lines 142-153 Link Here
142
  }
119
  }
143
120
144
  /**
121
  /**
145
   * <p>Convenience method to return the result of digesting the designated
122
   * Convenience method to return the result of digesting the designated input
146
   * input with a new instance of the SRP message digest algorithm.</p>
123
   * with a new instance of the SRP message digest algorithm.
147
   *
124
   * 
148
   * @param src some bytes to digest.
125
   * @param src some bytes to digest.
149
   * @return the bytes constituting the result of digesting the designated
126
   * @return the bytes constituting the result of digesting the designated input
150
   * input with a new instance of the SRP message digest algorithm.
127
   *         with a new instance of the SRP message digest algorithm.
151
   */
128
   */
152
  public byte[] digest(final byte[] src)
129
  public byte[] digest(final byte[] src)
153
  {
130
  {
Lines 157-169 Link Here
157
  }
134
  }
158
135
159
  /**
136
  /**
160
   * <p>Convenience method to return the result of digesting the designated
137
   * Convenience method to return the result of digesting the designated input
161
   * input with a new instance of the SRP message digest algorithm.</p>
138
   * with a new instance of the SRP message dige