Skip to content

Commit 80d0597

Browse files
committed
Add support for BasicAuth + alwaysSendBasicAuthHeaders in JsonServiceClient
1 parent 7c60dcd commit 80d0597

File tree

6 files changed

+1776
-1430
lines changed

6 files changed

+1776
-1430
lines changed

src/AndroidClient/client/src/main/java/net/servicestack/client/HttpHeaders.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
public class HttpHeaders {
77
public static final String Accept = "Accept";
8-
public static final String ContentType = "Content-Type";
8+
public static final String Authorization = "Authorization";
99
public static final String ContentLength = "Content-Length";
10+
public static final String ContentType = "Content-Type";
1011
}

src/AndroidClient/client/src/main/java/net/servicestack/client/JsonServiceClient.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ public class JsonServiceClient implements ServiceClient {
3333
String baseUrl;
3434
String replyUrl;
3535

36+
boolean alwaysSendBasicAuthHeaders;
37+
String userName;
38+
String password;
39+
3640
Integer timeoutMs;
3741
public ConnectionFilter RequestFilter;
3842
public ConnectionFilter ResponseFilter;
@@ -161,6 +165,10 @@ public HttpURLConnection createRequest(String requestUrl, String httpMethod, byt
161165
req.setRequestProperty(HttpHeaders.ContentType, requestType);
162166
}
163167

168+
if (alwaysSendBasicAuthHeaders) {
169+
addBasicAuth(req, userName, password);
170+
}
171+
164172
if (RequestFilter != null) {
165173
RequestFilter.exec(req);
166174
}
@@ -185,6 +193,11 @@ public HttpURLConnection createRequest(String requestUrl, String httpMethod, byt
185193
}
186194
}
187195

196+
private static void addBasicAuth(HttpURLConnection req, String userName, String password) {
197+
req.setRequestProperty(HttpHeaders.Authorization,
198+
"Basic " + Utils.toBase64String(userName + ":" + password));
199+
}
200+
188201
public static RuntimeException createException(HttpURLConnection res, int responseCode){
189202

190203
WebServiceException webEx = null;
@@ -259,6 +272,17 @@ public HttpURLConnection createSendRequest(Object request) {
259272
}
260273
}
261274

275+
@Override
276+
public void setAlwaysSendBasicAuthHeaders(boolean value) {
277+
this.alwaysSendBasicAuthHeaders = value;
278+
}
279+
280+
@Override
281+
public void setCredentials(String userName, String password) {
282+
this.userName = userName;
283+
this.password = password;
284+
}
285+
262286
@Override
263287
public <TResponse> TResponse send(IReturn<TResponse> request) {
264288
return send(

src/AndroidClient/client/src/main/java/net/servicestack/client/ServiceClient.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
import java.util.Map;
99

1010
public interface ServiceClient {
11+
void setAlwaysSendBasicAuthHeaders(boolean value);
12+
void setCredentials(String userName, String password);
13+
1114
<TResponse> TResponse send(IReturn<TResponse> request);
1215
void send(IReturnVoid request);
1316

src/AndroidClient/client/src/main/java/net/servicestack/client/Utils.java

Lines changed: 112 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,7 @@ public static boolean matchesContentType(String contentType, String matchesConte
529529
}
530530

531531
public static String sanitizeVarName(String name){
532-
return name.replaceAll("_","").toLowerCase();
532+
return name.replaceAll("_", "").toLowerCase();
533533
}
534534

535535
public static ResponseStatus createResponseStatus(Object obj) {
@@ -671,4 +671,115 @@ public static <K,V> HashMap<K,ArrayList<V>> createMap(ArrayList<V> xs, Function<
671671

672672
return to;
673673
}
674+
675+
//From: http://iharder.sourceforge.net/current/java/base64/ (Public Domain)
676+
public static String toBase64String(String source) {
677+
return toBase64String(toUtf8Bytes(source));
678+
}
679+
680+
public static String toBase64String(byte[] source) {
681+
byte[] encoded = toBase64Bytes(source);
682+
try {
683+
return new String(encoded, "US-ASCII");
684+
} catch (UnsupportedEncodingException e) {
685+
return new String(encoded);
686+
}
687+
}
688+
689+
public static byte[] toBase64Bytes(byte[] source) {
690+
return toBase64Bytes(source, 0, source.length);
691+
}
692+
693+
public static byte[] toBase64Bytes(byte[] source, int off, int len) {
694+
if (source == null)
695+
throw new NullPointerException("Cannot serialize a null array.");
696+
697+
if (off < 0)
698+
throw new IllegalArgumentException("Cannot have negative offset: " + off);
699+
700+
if (len < 0)
701+
throw new IllegalArgumentException("Cannot have length offset: " + len);
702+
703+
if (off + len > source.length)
704+
throw new IllegalArgumentException(String.format(
705+
"Cannot have offset of %d and length of %d with array of length %d", off, len, source.length));
706+
707+
int encLen = (len / 3) * 4 + (len % 3 > 0 ? 4 : 0); // Bytes needed for actual encoding
708+
byte[] outBuff = new byte[encLen];
709+
710+
int d = 0;
711+
int e = 0;
712+
int len2 = len - 2;
713+
for (; d < len2; d += 3, e += 4) {
714+
encode3to4(source, d + off, 3, outBuff, e);
715+
}
716+
717+
if (d < len) {
718+
encode3to4(source, d + off, len - d, outBuff, e);
719+
e += 4;
720+
}
721+
722+
// Only resize array if we didn't guess it right.
723+
if (e <= outBuff.length - 1) {
724+
byte[] finalOut = new byte[e];
725+
System.arraycopy(outBuff, 0, finalOut, 0, e);
726+
return finalOut;
727+
} else {
728+
return outBuff;
729+
}
730+
}
731+
732+
private final static byte EQUALS_SIGN = (byte)'=';
733+
734+
private final static byte[] _STANDARD_ALPHABET = {
735+
(byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
736+
(byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
737+
(byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
738+
(byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
739+
(byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
740+
(byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
741+
(byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
742+
(byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z',
743+
(byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5',
744+
(byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'+', (byte)'/'
745+
};
746+
747+
private static byte[] encode3to4(
748+
byte[] source, int srcOffset, int numSigBytes,
749+
byte[] destination, int destOffset) {
750+
751+
byte[] ALPHABET = _STANDARD_ALPHABET;
752+
753+
int inBuff = ( numSigBytes > 0 ? ((source[ srcOffset ] << 24) >>> 8) : 0 )
754+
| ( numSigBytes > 1 ? ((source[ srcOffset + 1 ] << 24) >>> 16) : 0 )
755+
| ( numSigBytes > 2 ? ((source[ srcOffset + 2 ] << 24) >>> 24) : 0 );
756+
757+
switch (numSigBytes)
758+
{
759+
case 3:
760+
destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ];
761+
destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
762+
destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>> 6) & 0x3f ];
763+
destination[ destOffset + 3 ] = ALPHABET[ (inBuff ) & 0x3f ];
764+
return destination;
765+
766+
case 2:
767+
destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ];
768+
destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
769+
destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>> 6) & 0x3f ];
770+
destination[ destOffset + 3 ] = EQUALS_SIGN;
771+
return destination;
772+
773+
case 1:
774+
destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ];
775+
destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
776+
destination[ destOffset + 2 ] = EQUALS_SIGN;
777+
destination[ destOffset + 3 ] = EQUALS_SIGN;
778+
return destination;
779+
780+
default:
781+
return destination;
782+
}
783+
}
784+
674785
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package net.servicestack.client.tests;
2+
3+
import junit.framework.TestCase;
4+
5+
import net.servicestack.client.JsonServiceClient;
6+
import net.servicestack.client.WebServiceException;
7+
8+
import net.servicestack.client.tests.testdtos.*;
9+
10+
/**
11+
* Created by mythz on 1/3/2016.
12+
*/
13+
public class TestAuthTests extends TestCase {
14+
15+
JsonServiceClient client = new JsonServiceClient("http://test.servicestack.net");
16+
17+
public void test_AuthRequired_returns_401(){
18+
try {
19+
client.get(new TestAuth());
20+
fail("should throw");
21+
} catch (WebServiceException ex){
22+
assertEquals(401, ex.getStatusCode());
23+
assertEquals("Unauthorized", ex.getStatusDescription());
24+
}
25+
}
26+
27+
public void test_does_send_BasicAuthHeaders(){
28+
client.setCredentials("test", "test");
29+
client.setAlwaysSendBasicAuthHeaders(true);
30+
31+
TestAuthResponse response = client.get(new TestAuth());
32+
33+
assertEquals("1", response.getUserId());
34+
assertEquals("test", response.getUserName());
35+
assertEquals("test DisplayName", response.getDisplayName());
36+
assertNotNull(response.getSessionId());
37+
}
38+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy