This is in regards to version 0.2 of the Kubernetes Java client. I'm guessing the way to use basic authentication in the Java API is to do this
ApiClient client = Config.fromUserPassword( "https://....:6443", "user", "password", false );
Configuration.setDefaultApiClient( client );
CoreV1Api api = new CoreV1Api();
// Make api call like
api.listNode(...)
However the above code always returns 403 Forbidden. From the response message, it doesn't look like the user/pass is being used in the request.
{"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"nodes is forbidden: User \"system:anonymous\" cannot list nodes at the cluster scope","reason":"Forbidden","details":{"kind":"nodes"},"code":403}
I also debugged through the code a bit and I may be answering my own question but it looks like in CoreV1Api's methods, it never add basic auth as an authentication method and only uses BearerToken. Is basic auth supported or should I be using another API class?
Many kubernetes clusters do not set up basic auth, only bearer token auth. Are you sure your cluster configured basic authentication?
https://kubernetes.io/docs/admin/authentication/#static-password-file
Answering my own question but it doesn't look like the current version of the client actually executes the user/pass authentication. BearerToken is working however.
The java client ignores the HttpBasicAuth object, but if you use the ApiKeyAuth object and set the key prefix to "Basic" and the API key to the base64 encoded credentials, it will work.
For example:
String credentials= new String(Base64.getEncoder().encode("user:password".getBytes()));
ApiClient defaultClient = Configuration.getDefaultApiClient();
defaultClient.setBasePath("https://256.256.256.256");
ApiKeyAuth fakeBearerToken = (ApiKeyAuth) defaultClient.getAuthentication("BearerToken");
fakeBearerToken.setApiKey(credentials);
fakeBearerToken.setApiKeyPrefix("Basic");
This works because the kubernetes client will simply concatenate the API key prefix with the prefix, and put the result in the "Authorization" header.
Related
I want to build a rest authentication endpoint with Jersey. I have already done it for a regular form on page:
#POST #Produces(MediaType.APPLICATION_JSON) #Path("/login")
#Consumes(MediaType.APPLICATION_FORM_URLENCODED) public Response login(
#FormParam("basicbtoatoken") String basicbtoatoken) {
.....
}
But, now I need to build an api that consumer login+pass and issues a token for further communications. How to do that properly in jersey? Can I just pass login+pass in open mode like other fields and process them accordingly? Or is there any trick for that?
Dead simple: basic auth ContainerRequestFilter. I'm sure you can find a reference implementation with some googling. If not, basic auth base 64 encodes credentials into authorization request header. Your back end credential store will be hit on every request to authenticate.
Nowadays this is typically solved via oauth2 protocol; a client gets a valid bearer token by various means. This is a short lived token added to the authorization header; encrypted with a trusted key (usually JWT) decoding it and checking basic sanity such as expiration is considered enough to authenticate. Credential store is only hit as often as you need to refresh this token (I've seen anything from 15 minutes into several hours)
I am using the Java class org.apache.hadoop.security.
authentication.server.AuthenticationFilter from Apache
Hadoop 2.5.0 as a filter in front of a Tomcat 6 Servlet we
wish to add Kerberos authentication to.
I am attempting to write some test cases against this filter
so that we have a better understanding of how it
works and what it does.
In order for the filter to authenticate a user, it is reading the
'Authorization' header of the HTTP request,
expecting the value to contain 'Negotiate '
My understanding of how Kerberos works leads me to believe that I
should be able to write code while creating my
HTTP request that looks something like this:
// normally the server principal keytab is not available from the client side,
// but for the purpose of making test cases I see no problem with sharing the keytab
// between the client side and the server side
javax.security.auth.kerberos.Keytab kt = KeyTab.getInstance("keytab");
KerberosKey keys[] = kt.getKeys("HTTP/voltage-pp-0000.albert.int#ALBERTS.INT");
SomeTokenType token = new SomeTokenType();
<code to set token parameters>
// my understanding of Kerberos is that the only cyphertext key
// needed on this token
// is one of the server principal's keys from the Keytab file
// (which does contain ~5
// keys of different sizes and types, I've checked)
EncryptedTokenType etoken = <encrypt token with a key from keys>
byte[] array = etoken.getBytes();
httprequest.addHeader("Authorization","Negotiate " + new Base64(0).encode(array));
So, questions here:
What is the Java Class that embodies the Kerberos Auth Token sent
in "Authorization Negotiate"?
What fields of that auth token have to be set to what values?
What is the encryption algorithm used to encrypt the auth token
against the keytab key?
What is the best keytab key to use?
What is the mechanism for byte-serializing the auth token, once
encrypted?
You are correct in that it is possible to "forge" a ticket in this manner. However, I know of no standard kerberos API that would do this.
You'll essentially need to reverse engineer the entire kerberos protocol to
create a service ticket based on the keytab. The service ticket format is
documented here
https://www.ietf.org/rfc/rfc4120.txt
You can use any of the keys in the keytab to encyrpt the service ticket. Once
you have the service ticket, you'll need to implement this RFC to create the
negotiation header.
https://www.rfc-editor.org/rfc/rfc4559
Generally, it's a lot simpler to just get a keytab for a client principal and use that and kinit to get a service ticket for testing. Your approach could work
and there is probably hacker code out there somewhere to implement it, but it's
an extremely non-standard way to do testing in a kerberos environment.
I have a url which needs authentication (like a browser pop up appears asking username and password.)
Generally, we can use the following format to achieve this:
http://username:password#url.com
Using RESTEasy client builder
Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://url.com");
How to achieve it without having to construct the http://username:password#url.com myself? I've seen if there are any methods which I could use to set it with no luck. Also I'm not sure how these credentials are passed, headers, cookies etc..
Looks like Basic Authentication. If that's the case, you just need to set the Authorization header to Basic base64encode(username:password).
For example:
String credentials = "username:password"
String base64encoded = Base64.getEncoder().encodeToString(credentials.getBytes());
Response response = target.request()
.header(HttpHeaders.AUTHORIZATION, "Basic " + base64encoded)....
The Base64 class I used is from Java 8. If you're not using Java 8, there are libraries that have Base64 support. Prior to Java 8, there's a com.sun internal Base64 class, but it's advised not to use those.
If you just want to run a quick test (and don't have Java 8 or don't want to go looking for a lib), you can go to this site and just type in your username:password and encode it, then just copy and paste to your code.
For example:
base64encode(username:password) == dXNlcm5hbWU6cGFzc3dvcmQ=
I have a dot net application that call a java web service. I am trying to implement authentication by passing credentials to the java service. Here is the dot net code setting the credentials. How can I get these credentials in my java application? They aren't set in the headers...
System.Net.NetworkCredential serviceCredentials = new NetworkCredential("user", "pass");
serviceInstance.Credentials = serviceCredentials;
serviceInstance is an instance of SoapHttpClientProtocol.
I've tried injecting the WebServiceContext like so
#Resource
WebServiceContext wsctx;
and pulling the crentials from the headers but they aren't there.
You are not passing the credentials to your service the correct way. In order to get the Authorize http request header do the following:
// Create the network credentials and assign
// them to the service credentials
NetworkCredential netCredential = new NetworkCredential("user", "pass");
Uri uri = new Uri(serviceInstance.Url);
ICredentials credentials = netCredential.GetCredential(uri, "Basic");
serviceInstance.Credentials = credentials;
// Be sure to set PreAuthenticate to true or else
// authentication will not be sent.
serviceInstance.PreAuthenticate = true;
Note: Be sure to set PreAuthenticate to true or else authentication will not be sent.
see this article for more information.
I had to dig-up some old code for this one :)
Update:
After inspecting the request/response headers using fiddler as suggested in the comments below a WWW-Authenticate header was missing at the Java Web Service side.
A more elegant way of implementing "JAX-WS Basic authentication" can be found in this article here using a SoapHeaderInterceptor (Apache CXF Interceptors)
Right now i'm using java to build rest service, and trying to use spring security to securing my service.
I have a few parameter that server needs to process the service (ex: application ID, username, password, consumer ID) . For username and password, I put in on http header "authorization", encoded with base64. Is there a way to put another parameters above (ex. AppID, consID) into http header?
Some sample of code would help, thanks.
You can put whatever you want in a whatever header you like. You can create custom headers. So you can have a App-Id header where you pass the appId. Alternatively you can pass those as parameters in the URL. That way you'll get rid of the option that some (stupid) proxy trims your headers.
Btw, I would suggest not to send the password, unless you are using https. Generally, I can recommend two similar scenarios:
use OAuth - let the user grant access to the API client via the OAuth dance. The client ends up with a token which it uses on each request.
use a custom, simplified token scheme - login once (with username and password, over https), and send a short-lived token in response. Each subsequent request can be made over an unsecured connection by providing the token, and (optionally) some HMAC of the request parameters, using a consumer secret as a key, so that you can verify the client is legit.