You extend the Authenticator class and register it. The javadocs at the link explain how.
I don't know if this works with the nio method that got the accepted answer to the question, but it for sure works for the old fashioned way that was the answer under that one.
Within the authenticator class implementation, you are probably going to use a PasswordAuthentication and override the getPasswordAuthentication() method of your Authenticator implementation to return it. That will be the class which is passed the user name and password you need.
Per your request, here is some sample code:
public static final String USERNAME_KEY = "username";
public static final String PASSWORD_KEY = "password";
private final PasswordAuthentication authentication;
public MyAuthenticator(Properties properties) {
String userName = properties.getProperty(USERNAME_KEY);
String password = properties.getProperty(PASSWORD_KEY);
if (userName == null || password == null) {
authentication = null;
} else {
authentication = new PasswordAuthentication(userName, password.toCharArray());
}
}
protected PasswordAuthentication getPasswordAuthentication() {
return authentication;
}
And you register it in the main method (or somewhere along the line before you call the URL):
Authenticator.setDefault(new MyAuthenticator(properties));
The usage is simple, but I find the API convoluted and kind of backwards for how you typically think about these things. Pretty typical of singleton design.
Answer from Yishai on Stack OverflowYou extend the Authenticator class and register it. The javadocs at the link explain how.
I don't know if this works with the nio method that got the accepted answer to the question, but it for sure works for the old fashioned way that was the answer under that one.
Within the authenticator class implementation, you are probably going to use a PasswordAuthentication and override the getPasswordAuthentication() method of your Authenticator implementation to return it. That will be the class which is passed the user name and password you need.
Per your request, here is some sample code:
public static final String USERNAME_KEY = "username";
public static final String PASSWORD_KEY = "password";
private final PasswordAuthentication authentication;
public MyAuthenticator(Properties properties) {
String userName = properties.getProperty(USERNAME_KEY);
String password = properties.getProperty(PASSWORD_KEY);
if (userName == null || password == null) {
authentication = null;
} else {
authentication = new PasswordAuthentication(userName, password.toCharArray());
}
}
protected PasswordAuthentication getPasswordAuthentication() {
return authentication;
}
And you register it in the main method (or somewhere along the line before you call the URL):
Authenticator.setDefault(new MyAuthenticator(properties));
The usage is simple, but I find the API convoluted and kind of backwards for how you typically think about these things. Pretty typical of singleton design.
This is some code I wrote that fetches a website and displays the contents to System.out. It uses Basic authentication:
import java.net.*;
import java.io.*;
public class foo {
public static void main(String[] args) throws Exception {
URL yahoo = new URL("http://www.MY_URL.com");
String passwdstring = "USERNAME:PASSWORD";
String encoding = new
sun.misc.BASE64Encoder().encode(passwdstring.getBytes());
URLConnection uc = yahoo.openConnection();
uc.setRequestProperty("Authorization", "Basic " + encoding);
InputStream content = (InputStream)uc.getInputStream();
BufferedReader in =
new BufferedReader (new InputStreamReader (content));
String line;
while ((line = in.readLine()) != null) {
System.out.println (line);
}
in.close();
}
Problems with the above code:
This code isn't production-ready (but it gets the point across.)
The code yields this compiler warning:
foo.java:11: warning: sun.misc.BASE64Encoder is Sun proprietary API and may be removed in a future release
sun.misc.BASE64Encoder().encode(passwdstring.getBytes());
^ 1 warning
One really should use the Authenticator class, but for the life of me, I could not figure out how and I couldn't find any examples either, which just goes to show that the Java people don't actually like it when you use their language to do cool things. :-P
So the above isn't a good solution, but it does work and could easily be modified later.
Java: Download file from URL when URL requests authentication - Stack Overflow
JAVA: Trying to download file from URL with authentication - Stack Overflow
java - File download involving HTTP Basic Authentication - Stack Overflow
authentication - Download large files with java from authenticated server - Stack Overflow
Or, if you want to be safe about it:
HttpResponse res;
DefaultHttpClient httpclient = new DefaultHttpClient();
String authorizationString = "Basic " + Base64.encodeToString(("admin" + ":" + "").getBytes(), Base64.NO_WRAP); //this line is diffe
authorizationString.replace("\n", "");
try {
HttpGet request = new HttpGet(URI.create(url));
request.addHeader("Authentication",authorizationString);
res = httpclient.execute(request);
return new MjpegInputStream(res.getEntity().getContent());
} catch (ClientProtocolException e) {e.printStackTrace();}
} catch (IOException e) {e.printStackTrace();}
If the server uses BASIC authentication, you should be able to get the resource by specifying username/password in the URL: http://user:password@hostname/path/filename.ext
Browsers support this too, so you can try it in your browser quickly.
Highly recommend Apache HTTP Client
finally, I solved the problem using this function:
public void download(String url, String outPath, String authBase64) throws IOException {
URL server = new URL(url);
URLConnection connection = (URLConnection) server.openConnection();
connection.setRequestProperty("Authorization", "Basic " + authBase64);
connection.connect();
InputStream is = connection.getInputStream();
FileOutputStream fos = new FileOutputStream(new File(outPath));
byte[] buffer = new byte[4096];
int n = 0;
while (-1 != (n = is.read(buffer))) {
fos.write(buffer, 0, n);
}
is.close();
fos.close(); }
This is what I came up with helped by S201's answer plus a lot of googling. The code is simplified and without try-catch constructions.
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost("https://example.com/login");
HttpResponse response = null;
List<NameValuePair> postFields = new ArrayList<NameValuePair>(2);
// Set the post fields
postFields.add(new BasicNameValuePair("username", "myusername"));
postFields.add(new BasicNameValuePair("password", "mypassword"));
post.setEntity(new UrlEncodedFormEntity(postFields, HTTP.UTF_8));
// Execute the POST request
response = client.execute(post);
// Now GET the file
HttpGet get = new HttpGet("http://example.com/files/myfile.mp3");
response = client.execute(get);
HttpEntity entity = response.getEntity();
InputStream in = entity.getContent();
// Save the file to SD
File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
path.mkdirs();
File file = new File(path, "myfile.mp3");
FileOutputStream fos = new FileOutputStream(file);
byte[] buffer = new byte[1024];
int len1 = 0;
while ((len1 = in.read(buffer)) > 0) {
fos.write(buffer, 0, len1);
}
fos.close();
You going to want to use an HttpClient object in combination with HttpPost, HttpGet, and HttpResponse objects. It is probably easier to just look at an example.
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(context.getString(R.string.loginURL));
HttpResponse response = null;
List<NameValuePair> postFields = new ArrayList<NameValuePair>(2);
// Set the post fields
postFields.add(new BasicNameValuePair("username", settings.getString("username", "null")));
postFields.add(new BasicNameValuePair("password", settings.getString("password", "null")));
post.setEntity(new UrlEncodedFormEntity(postFields, HTTP.UTF_8));
// Execute the POST request
response = client.execute(post);
Assuming the login was successful, you can now execute GET and POST requests as an authenticated user as long as you execute them though the HttpClient that you executed the login through. It is this object that manages the cookies. Hope this helps!
EDIT: Forgot to mention that you can of course use the HttpRespose object to perform error checking.
You may be having certificate issues. This is typically the problem I have encountered in the past when working with HTTPS connections in Java.
First, you should check and see if the URL to which you are attempting to connect has a signed certificate by a well-known trusted root CA, and is valid (not expired).
I would recommend opening the URL in your browser and checking the certificate information.
Just a FYI, there may be a disconnect between the Trusted Root CAs recognized by your browser and those recognized by Java. Here is another Stackoverflow question about how to get those recognized by Java: How can I get a list of trusted root certificates in Java?
If this is a self-signed certificate, then there are hoops you will need to jump through regarding importing it into and using a local Keystore. There are numerous sites and blogs that guide you through doing this, here is one such blog (not mine): Adding self-signed https certificates to java keystore
Also, while you are testing with the browser, this will help you verify that there are no proxy issues. You should definitely check your browser's settings to determine whether or not you are going through a proxy server.
You should definitely look into using HttpClient instead of java.net.URL. Here is the Apache page for HttpClient 4.2.1.
Finally, if you are looking to do a file transfer via HTTP or HTTPS, you may want to consider WebDAV.
I have used Jakarta Slide WebDAV Client for this in the past. Unfortunately, it looks like Slide is retired at this point, but there are alternatives you can find with a little bit of searching.
ADDITION
I copied down your source code sample and looked at it more closely. Looks like you set properties for http, but not https.
HTTPS has separate properties:
- https.proxyHost
- https.proxyPort
Try setting:
System.setProperty("https.proxyHost","trproxy.rwe.com") ;
System.setProperty("https.proxyPort", "443") ;
Look at section 2.2 on Oracle's Java Networking and Proxies.
http://docs.oracle.com/javase/6/docs/technotes/guides/net/proxies.html
Looks like your problem could be with the proxy. It should also support https. Also, you should use HttpClient 4 for downloading the files, its a mature library for making http connections.
I found the answer myself. Using HttpURLConnection, this method can be used to "authenticate" to a variety of services. I used chrome's build in networking tools to get the cookie values of the GET request.
HttpURLConnection con = (HttpURLConnection) new URL("https://www.shazam.com/myshazam/download-history").openConnection();
con.setRequestMethod("GET");
con.addRequestProperty("Cookie","registration=Cooki_Value_Here;profile-data=Cookie_Value_Here");
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();
So if you delete those cookies/use a private session, the browser should reproduce what you are seeing in code.
I'm guessing you need to first go to "http://www.shazam.com/myshazam" and log in.