PlainSaslServer.java
001 /*
002  *
003  * Licensed to the Apache Software Foundation (ASF) under one
004  * or more contributor license agreements.  See the NOTICE file
005  * distributed with this work for additional information
006  * regarding copyright ownership.  The ASF licenses this file
007  * to you under the Apache License, Version 2.0 (the
008  * "License"); you may not use this file except in compliance
009  * with the License.  You may obtain a copy of the License at
010  
011  *   http://www.apache.org/licenses/LICENSE-2.0
012  
013  * Unless required by applicable law or agreed to in writing,
014  * software distributed under the License is distributed on an
015  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016  * KIND, either express or implied.  See the License for the
017  * specific language governing permissions and limitations
018  * under the License.
019  *
020  */
021 package org.apache.qpid.server.security.auth.sasl.plain;
022 
023 import java.io.IOException;
024 
025 import javax.security.auth.callback.Callback;
026 import javax.security.auth.callback.CallbackHandler;
027 import javax.security.auth.callback.NameCallback;
028 import javax.security.auth.callback.PasswordCallback;
029 import javax.security.auth.callback.UnsupportedCallbackException;
030 import javax.security.sasl.AuthorizeCallback;
031 import javax.security.sasl.SaslException;
032 import javax.security.sasl.SaslServer;
033 
034 public class PlainSaslServer implements SaslServer
035 {
036     public static final String MECHANISM = "PLAIN";
037 
038     private CallbackHandler _cbh;
039 
040     private String _authorizationId;
041 
042     private boolean _complete = false;
043 
044     public PlainSaslServer(CallbackHandler cbh)
045     {
046         _cbh = cbh;
047     }
048 
049     public String getMechanismName()
050     {
051         return MECHANISM;
052     }
053 
054     public byte[] evaluateResponse(byte[] responsethrows SaslException
055     {
056         try
057         {
058             int authzidNullPosition = findNullPosition(response, 0);
059             if (authzidNullPosition < 0)
060             {
061                 throw new SaslException("Invalid PLAIN encoding, authzid null terminator not found");
062             }
063             int authcidNullPosition = findNullPosition(response, authzidNullPosition + 1);
064             if (authcidNullPosition < 0)
065             {
066                 throw new SaslException("Invalid PLAIN encoding, authcid null terminator not found");
067             }
068 
069             // we do not currently support authcid in any meaningful way
070             // String authcid = new String(response, 0, authzidNullPosition, "utf8");
071             String authzid = new String(response, authzidNullPosition + 1, authcidNullPosition - 1"utf8");
072 
073             // we do not care about the prompt but it throws if null
074             NameCallback nameCb = new NameCallback("prompt", authzid);
075             PasswordCallback passwordCb = new PasswordCallback("prompt"false);
076             // TODO: should not get pwd as a String but as a char array...
077             int passwordLen = response.length - authcidNullPosition - 1;
078             String pwd = new String(response, authcidNullPosition + 1, passwordLen, "utf8");
079             AuthorizeCallback authzCb = new AuthorizeCallback(authzid, authzid);
080             Callback[] callbacks = new Callback[]{nameCb, passwordCb, authzCb};
081             _cbh.handle(callbacks);
082             String storedPwd = new String(passwordCb.getPassword());
083             if (storedPwd.equals(pwd))
084             {
085                 _complete = true;
086             }
087             if (authzCb.isAuthorized() && _complete)
088             {
089                 _authorizationId = authzCb.getAuthenticationID();
090                 return null;
091             }
092             else
093             {
094                 throw new SaslException("Authentication failed");
095             }
096         }
097         catch (IOException e)
098         {
099             throw new SaslException("Error processing data: " + e, e);
100         }
101         catch (UnsupportedCallbackException e)
102         {
103             throw new SaslException("Unable to obtain data from callback handler: " + e, e);
104         }
105     }
106 
107     private int findNullPosition(byte[] response, int startPosition)
108     {
109         int position = startPosition;
110         while (position < response.length)
111         {
112             if (response[position== (byte0)
113             {
114                 return position;
115             }
116             position++;
117         }
118         return -1;
119     }
120 
121     public boolean isComplete()
122     {
123         return _complete;
124     }
125 
126     public String getAuthorizationID()
127     {
128         return _authorizationId;
129     }
130 
131     public byte[] unwrap(byte[] incoming, int offset, int lenthrows SaslException
132     {
133         throw new SaslException("Unsupported operation");
134     }
135 
136     public byte[] wrap(byte[] outgoing, int offset, int lenthrows SaslException
137     {
138         throw new SaslException("Unsupported operation");
139     }
140 
141     public Object getNegotiatedProperty(String propName)
142     {
143         return null;
144     }
145 
146     public void dispose() throws SaslException
147     {
148         _cbh = null;
149     }
150 
151 }