I am using java.net.HttpURLConnection, and it annoyingly presents a window asking for username and password whenever a 401 response code is returned by the HTTP server.
How can I get rid of this automatic auth dialog? I want to handle 401s myself.
I tried setAllowUserInteraction(false), but it seems to have no effect.
The popup comes from the default authenticator. To remove the popup, you can plug in your own authenticator. See How to handle HTTP authentication using HttpURLConnection?
#mdma's answer is correct, you can plug in your own Authenticator to handle authentication, so that there's no popup.
If you're already handling authentication in another way (such as by connection.setRequestProperty("Authorization", ...), as this answer to another question describes), you can use Authenticator.setDefault() to choose to not to use any Authenticator for authentication:
Authenticator.setDefault(null);
This removes the old default Authenticator, so that if your authentication is wrong, you get the error response code via your URLConnection, without opening any popup.
An equivalent way is to set the default to an Authenticator which returns null for getPasswordAuthentication() (which is the default implementation), as in the following code:
Authenticator.setDefault(new Authenticator() { });
But unless you're going to add code to your Authenticator, I don't see a reason to choose this over null.
Related
In certain cases we need to skip automatic login through Kerberos.
According to the documentation this should be done through the parameter ?prompt=login:
prompt - Keycloak supports these settings:
login - SSO will be ignored and the Keycloak login page will be always shown, even if the user is already authenticated
This works in most cases (we also use a NTLM waffle implementation) but with Kerberos the user is always signed in automatically.
Any hint or idea why? Are there alternative ways to force forwarding to the login page?
EDIT: The reason I need to skip the Kerberos authentication is because I need to login with an admin-account where I have to enter username+password.
EDIT2: We are using Keycloak.x version 14.0.0, also applies to version 15.0.2.
The parameter ?prompt=login will only skip the Cookie authenticator in your authentication flow. Execution of the Cookie authenticator will be marked as attempted but not as successful. So Keycloak will fallback to an alternative authenticator. I am assuming the Kerberos authenticator is configured as an alternative. If this is the case, you will be (automatically) authenticated by the Kerberos authenticator.
If you only need this behaviour for a particular client, you may want to create an additional authentication flow for that client without the Kerberos authenticator. Use Authentication flow overrides to configure the new flow for the client.
I just created a feature-request with a possible solution on the code side.
skip kerberos SSO authentication to use login-form
Might be able to override the default SpnegoAuthenticator with a custom one containing the login parameter handling.
I patched and tested it in a kerberos environment and it worked.
#Override
public void authenticate(AuthenticationFlowContext context) {
// +++ BEGIN CHANGE +++
AuthenticationSessionModel session = context.getAuthenticationSession();
Map<String, String> clientNotes = session.getClientNotes();
if ("login".equals(clientNotes.get("prompt"))) {
logger.info("skip SPNEGO authenticator because of client requests login prompt: " + clientNotes); //$NON-NLS-1$
context.attempted();
return;
}
// +++ END CHANGE +++
HttpRequest request = context.getHttpRequest();
String authHeader = request.getHttpHeaders().getRequestHeaders().getFirst(HttpHeaders.AUTHORIZATION);
if (authHeader == null) {
Response challenge = challengeNegotiation(context, null);
context.forceChallenge(challenge);
return;
}
I'm using HttpURLConnection class to manage HTTP connections in my Android app. Problem is, on some servers, I have a code 401 using an URL which working on a Internet navigator. I initialize connection with basic authentication, but I think these servers need an other mode. I know it works with libCURL and the following instruction:
curl_easy_setopt(pCurlHandle, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
But is there an way to doing something like that on Android? Currently, I do that:
...
connection.setRequestProperty("Authorization", "Basic " + Base64.encode("username:password"));
...
I tried with Authenticator too:
Authenticator.setDefault(new Authenticator() {
#Override
protected PasswordAuthentication getPasswordAuthentication()
{
return new PasswordAuthentication("username", "password".toCharArray());
}
});
But I still have a 401 in my app. Any idea?
Well, this post really helped me (but I don't use Authenticator class at all) and now my code do the job like that (if authentication is needed):
Initialize my HttpURLConnection object with Basic authentication (see the first Java sample in my question's code)
Test if I receive a code 401 and if it is, check if server was excepted for a Digest authentication analyzing response headers.
Retry with a manually-built Digest request property (see the post I mentioned)
And it works!
I hope this answer'll help someone!
I'm beginner with OpenAM, I'm working on an existing project.
I use this documentation to improve our authentication service:
http://docs.forgerock.org/en/openam/10.0.0/dev-guide/index/chap-authentication.html
The login works fine, I receive my token Id and add it in the cookies. I stay connected when I browse restricted web pages.
Now I want to do a clean logout.
When you read the documentation about logout, they propose this code:
protected void logout(AuthContext lc)
throws AuthLoginException {
lc.logout();
System.out.println("Logged Out!!");
}
But in my program, I do not have the login AuthContext anymore.
Is there a way to get or create an AuthContext associated with my user ? This call is it necessary ? (actually, We modify the cookies to be rejected by OpenAM)
Thank you.
Answer:
SSOToken ssoToken = SSOTokenManager.getInstance().createSSOToken(tokenId);
AuthContext authContext = new AuthContext(ssoToken);
authContext.logout();
Firstly I think you should be able to create a new AuthContext by having access to the session token, by using this constructor.
Secondly it is not necessary to use the ClientSDK to perform authentication remotely, you could also just use the REST APIs, which probably would be a bit more lightweight.
I am using Restlet with Digest Authentication. Works well. Except I want to make it a bit more ajax/Javascript friendly by avoiding the browser's authentication dialog pop up when a 401 is first sent back.
This is what I think will work:
User/pass obtained using a textfields and stored in javascript object.
Ajax call to secure resource.
Reselt sends back non-401 code (say 406) with Digest Auth info.
Javascript catches code, packages request/user/password into hash, sends to restlet.
a) Will the above work?
b) How do I send a different status code using Digest in Restlet?
Yes, you have to return non-401 response, since you cannot change the browser behaviour in that the browser will always display the popup.
see also How to prevent browser to invoke basic auth popup and handle 401 error using Jquery?
you change the response by modifying/overriding the DigestAuthenticator and setting a different response, or use a filter that will detect a 401 and switch it to another status.
We have a JSF web application that uses Acegi security. We also have a standalone Java Swing application. One function of the Swing app is to load the user's home page in a browser window.
To do this we're currently using Commons HttpClient to authenticate the user with the web app:
String url = "http://someUrl/j_acegi_security_check";
HttpClient client = new HttpClient();
System.setProperty(trustStoreType, "Windows-ROOT");
PostMethod method = new PostMethod(url);
method.addParameter("j_username", "USERNAME");
method.addParameter("j_password", "PASSWORD");
int statusCode = client.executeMethod(method);
if (statusCode == HttpStatus.SC_MOVED_TEMPORARILY ) {
Header locationHeader= method.getResponseHeader("Location");
String redirectUrl = locationHeader.getValue();
BrowserLauncher launcher = new BrowserLauncher();
launcher.openURLinBrowser(redirectUrl);
}
This returns a HTTP 302 redirect response, from which we take the redirect url and open it using BrowserLauncher 2. The url contains the new session ID, something like:
http://someUrl/HomePage.jsf;jsessionid=C4FB2F643CE48AC2DE4A8A4C354033D4
The problem we're seeing is that Acegi processes the redirect but throws an AuthenticationCredentialsNotFoundException. It seems that for some reason the authenticated credentials cannot be found in the security context.
Does anyone have an idea as to why this is happening? If anyone needs more info then I'll be happy to oblige.
Many thanks,
Richard
I have never done Acegi/SpringSecurity, but the symptoms are clear enough: some important information is missing in the request. You at least need to investigate all the response headers if there isn't something new which needs to be passed back in the header of the subsequent request. Maybe another cookie entry which represents the Acegi credentials.
But another caveat is that you in fact cannot open just the URL in a local browser instance, because there's no way to pass the necessary request headers along it. You'll need to have your Swing application act as a builtin webbrowser. E.g. get HTML response in an InputStream and render/display it somehow in a Swing frame. I would check if there isn't already an existing API for that, because it would involve much more work than you'd initially think .. (understatement).
In this case you can do Basic Authentication and set this header in every request instead of sending the jsessionid:
AUTHORIZATION:Basic VVNFUk5BTUU6UEFTU1dPUkQ=
The token VVNFUk5BTUU6UEFTU1dPUkQ= is the username and the password encoded base64.
Example:
scott:tiger
is:
c2NvdHQ6dGlnZXI=
One more thing: use SSL.