Restlet ChallengeResponse null on server side when using GWT - authentication

We're trying to send Google Authentication tokens to our Rest interface on Google App Engine.
As explained here (under heading "Calling a Google API")
https://developers.google.com/accounts/docs/OAuth2InstalledApp
We should do this by including an Authorization: Bearer HTTP header.
On the client side we're using;
public ClientResource getClientResource(Reference pReference, String pAccessToken)
{
ClientResource lClientResource = new ClientResource(pReference);
ChallengeResponse lChallengeResponse = new ChallengeResponse(ChallengeScheme.HTTP_OAUTH_BEARER);
lChallengeResponse.setRawValue(pAccessToken);
lClientResource.setChallengeResponse(lChallengeResponse);
return lClientResource;
}
So the ChallengeResponse with setRawValue() is used to set the header;
ChallengeResponse lChallengeResponse = new ChallengeResponse(ChallengeScheme.HTTP_OAUTH_BEARER);
lChallengeResponse.setRawValue(pAccessToken);
lClientResource.setChallengeResponse(lChallengeResponse);
For our J2SE clients this is working. Although there's an error message;
"Challenge scheme HTTP_Bearer not supported by the Restlet engine."
we're able to read the token on the server side with;
ChallengeResponse lChallengeResponse = pRequest.getChallengeResponse();
String lAccessToken = lChallengeResponse.getRawValue();
While this is working for our J2SE clients, our GWT clients always return lChallengeResponse == null
Is this the correct method to set the Authorization: Bearer HTTP header or should we add extra/other configuration options?
Why isn't this working for our GWT clients (return null)?
How do we get rid of the error message on our J2Se clients?

Related

ServiceStack API aspnet core with Azure AD B2C returns 401 for request even with bearer token

I have a working ServiceStack API that authenticates against a AzureAD tenant. We are trying to move this to start using Azure B2C. The application is build with c# and runs on net 5.0. I've managed to change the configuration to use the 'correct' config. I'm then using Postman to get my access token from my tenant suing the authorization code flow.
However, when i make a request to the api, the response is always a 401 status code.
Where in the servicestack code can I put a break point to see why this failure is happening? I have tried multiple places in our AppHostConfigurator.cs/AppHost.cs files, but the break points doesn't appear to display why a 401 is being sent back as a response. I'm sure it's something related to wrong claims/roles expected etc, maybe the Azure ADB2C application being setup incorrectly, but obviously i need to know exactly so that i can resolve.
I'm setting up the authentication like this:
private static void ConfigureAuthentication(IAppHost host)
{
var authProviders = new List<IAuthProvider> {new NetCoreIdentityAuthProvider(host.AppSettings)};
if (host.AppSettings.GetAllKeys().Contains("AzureAdB2C"))
{
var debugMode = host.AppSettings.Get(nameof(HostConfig.DebugMode), false);
var azureSettings = host.AppSettings.Get<AzureAdB2COptions>("AzureAdB2C");
var jwt = azureSettings.GetB2CJWTProviderReader(debugMode);
jwt.PopulateSessionFilter = (session, payload, request) =>
{
if (session.Email == null && payload.ContainsKey("upn") && payload["upn"].Contains("#"))
session.Email = payload["upn"];
if (session.UserName == null && payload.ContainsKey("unique_name"))
session.UserName = payload["unique_name"];
};
authProviders.Add(jwt);
}
var auth = new AuthFeature(() => new AuthUserSession(), authProviders.ToArray())
{
HtmlRedirect = "/account/signin",
HtmlLogoutRedirect = "/account/signout",
IncludeAssignRoleServices = false,
IncludeRegistrationService = false
};
// remove default service authentication services
auth.ServiceRoutes.Remove(typeof(AuthenticateService));
host.Plugins.Add(auth);
}
We are using swagger as well to call the API (which works as expected). This question is more about that requests that are submitted with a bearer token.
thanks
Please refer to this existing answer for examples of how to validate why a 3rd Party JWT Token is invalid with ServiceStack's JWT Auth Provider.

How to specify Restlet customer HTTP header with key as "Authorization"

I am using Restlet2.3 to run REST API test automation.
The new feature has a customer HTTP header to pass a token to the service.
Form headers = (Form)resource.getRequestAttributes().get("org.restlet.http.headers");
if (headers == null) {
headers = new Form();
resource.getRequestAttributes().put("org.restlet.http.headers", headers);
}
...
headers.add(key, value);
The code works. Now, the customer HTTP header is defined as "Authorization". The above code seems not passing the header properly. And this is not challengeScheme involved.
I tested this scenario on SoapUI and Postman. Both work.
Anyone knows that restlet support this?
In fact, you can't override standard headers like Authorization with Restlet when doing a request.
If you want to provide a security token, you could use this approach:
String pAccessToken = "some token";
ChallengeResponse challengeResponse = new ChallengeResponse(
new ChallengeScheme("", ""));
challengeResponse.setRawValue(pAccessToken);
clientResource.setChallengeResponse(challengeResponse);
This way you'll have only the token in the Authorization header (with a space at the beginning - so don't forget to trim the value).

Implement Authentication for servlet on publish instance CQ5/AEM

I have a scenario and any suggestions in implementing that will be of great help. I have a servlet created on publish that will have POST requests coming from a lot of other third party applications. This servlet just stores the incoming posted data in JCR. I have successfully created this servlet but now the requirement is to make this servlet secured so that only applications hitting this servlet with particular username and password should be entertained.
What can I do to achieve this?
The way I would go for it:
Ask those 3rd party applications to send you the username and password so you can validate them on your servlet, then decide if you will allow or reject the request.
from the servlet calling (the 3rd party application)
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// ...
request.setAttribute("username", "a_valid_user");
request.setAttribute("password", "a_valid_password");
request.getRequestDispatcher("yourApp/YourServlet").forward(req, resp);
}
On your servlet:
String username = request.getParameter("username");
String password = request.getParameter("password");
if("a_valid_user".equals(username) && "a_valid_password".equals(password) {
// validate and go further
} else {
// do not process the request
}
The above example is valid just in case you can validate them on your side.
If this sample doesn't answer to your question, please provide more information about those 3rd party applications and the way you want to validate them.
You might consider using Google Client Library. I used it for authentication of users in an AEM publish instance. After the third party server is authenticated, you could use a separate AEM service account to handle POST processing.
Here' a SO post I made about integrating those libraries into AEM.
Google Client API in OSGI
With this you should be able set up authentication of the third party service account... as discussed here
https://developers.google.com/identity/protocols/OAuth2ServiceAccount
I haven't actually done server to server auth in AEM, but it should be possible. But in a separate project (non AEM) I've used the Google Client Library for authenticating Service Accounts.
I recommend to use a two step process:
Step 1: Authentication and generate a token, you can use 3rd party service also to generate token.
Step 2: Call your servlet with this token, the servlet will validate token first and then use post data.
Thanks everyone for your replies. In the end I implemented the below code for authentication in cq :
final String authorization = request.getHeader("Authorization");
if (authorization != null && authorization.startsWith("Basic")) {
StringTokenizer st = new StringTokenizer(authorization);
if (st.hasMoreTokens()) {
String basic = st.nextToken();
if (basic.equalsIgnoreCase("Basic")) {
String decodedStr = Base64.decode(st.nextToken());
LOGGER.info("Credentials: " + decodedStr);
int p = decodedStr.indexOf(":");
if (p != -1) {
String login = decodedStr.substring(0, p).trim();
String password = decodedStr.substring(p + 1).trim();
Credentials credentials = new SimpleCredentials(login, password.toCharArray());
adminSession = repository.login(credentials);
if (null != adminSession) {
// means authenticated and do your stuff here
}
}
}
}
}
Also in the webservice code which is calling the servlet of publish, below is the code on how I am supplying the credentials in auth headers :
String authStr = usrname+":"+password;
// encode data on your side using BASE64
byte[] bytesEncoded = Base64.encodeBase64(authStr.getBytes());
String authEncoded = new String(bytesEncoded);
connection.setRequestProperty("Authorization", "Basic "+authEncoded);
connection.setDoOutput(true);
connection.setRequestMethod("POST");
OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream());
writer.write("jsondata={sample:jsoncontent}");
writer.close();

thinktecture identity server 3 authentication works correctly in iis express, but keeps on throwing 401 unatuhorized when hosted in iis

Ok so i tried hosting the simplest oauth sample and the identity server both on iis, i have enable cors on the simplest oauth sample. So when i test the api using the javascript implicit client, on iis express it works flawlessly, it gets the token then when the token is sent the web api checks the token and authorizes the javascript client. the problem happens when i move the javascript imlicit client, the identity server, and the simple oath web api is hosted on iis, the javascript brings back the token correctly but when the token is sent to the web api it always return 401 unauthorized. So is there any configuration i have to add in order to run it on iis. i have made sure that anonymous authentication is the only enab;ed authentication mode. Any help or pointer is deeply appreciate.
I am trying to implement the samples given on iis. thanks for the help
I had the same issue. It was coming from my self signed certificate.
Try adding to your IdentityServerOptions
RequireSsl = false
and switch the WebApi Authority to use http.
Edit
Server Side Configuration
public void ConfigureIdentityServer(IAppBuilder app)
{
//Configure logging
LogProvider.SetCurrentLogProvider(new DiagnosticsTraceLogProvider());
//This is using a Factory Class that generates the client, user & scopes. Can be seen using the exmaples
var IdentityFactory = Factory.Configure("DefaultConnection");
app.Map("/identity", idsrvApp =>
{
idsrvApp.UseIdentityServer(new IdentityServerOptions
{
SiteName = "Security Proof of Concept",
SigningCertificate = LoadCertificate(),
Factory = IdentityFactory,
CorsPolicy = CorsPolicy.AllowAll,
RequireSsl = false
});
});
}
JavaScript
After receiving the token make sure it's inserted in the Authorization Header..
JQuery Example
$.ajax({
url: 'http://your.url',
type: GET,
beforeSend: function (xhr) {
xhr.withCredentials = true;
xhr.setRequestHeader("Authorization", " Bearer " + apiToken);
}
});
WebApi Resource
app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
{
//Location of identity server make full url & port
Authority = "http://localhost/identity",
RequiredScopes = new[] { "WebApiResource" }
//Determines if the Api Pings the Identity Server for validation or will decrypt token by it's self
//ValidationMode = ValidationMode.Local
});
Best way to determine what is happening is enable logging.

ServiceStack JsonServiceClient send basic instead of Basic for Authorization header

I am using the JsonServiceClient client to talk to a RESTful service hosted on IIS 7 by an external vendor.
Here is some sample code I am using to call their Get method.
ServiceStack.ServiceClient.Web.JsonServiceClient client = new ServiceStack.ServiceClient.Web.JsonServiceClient("UrlToVendor"));
client.SetCredentials("userName", "password");
client.AlwaysSendBasicAuthHeader = true;
DTOReturn result = client.Get<DTOReturn>(string.Empty);
I always get an authorization failure. We put a sniffer and the Authorization header is being sent as:
basic userName:password
instead of
Basic userName:password
We were able to use standard .Net calls to get it to work
System.Net.HttpWebRequest req = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(
"UrlToVendor");
string authInfo = "userName:password";
authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo));
req.Accept = "application/json"; //text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
req.PreAuthenticate = true;
req.Method = "GET";
req.Headers["Authorization"] = string.Format("Basic {0}", authInfo);
System.Net.HttpWebResponse res = (System.Net.HttpWebResponse)req.GetResponse();
And these standard calls failed the same as the JasonServiceClient if we changed "Basic" to "basic".
Any suggestions?
Looks like someone had the same problem. This recent commit changed the auth-scheme from "basic" to "Basic". https://github.com/ServiceStack/ServiceStack/commit/d4f21c5355ab87d7315e142372eef9a40e096b5f
You should be able to just update your dlls.
According to RFC 2617 sec 1.2 the auth-scheme is case-insensitive.
See https://www.rfc-editor.org/rfc/rfc1945#page-47. I would be curious as to why the vendor service won't accept it.