I'm working on a Java API that functions as an endpoint API, and on production
it runs on the Google Cloud Platform. API methods are called by passing a Firebase token as part of the URL, and the token is used to create a User that's available inside the API method:
#ApiMethod(path = "myPath/{tokenId}/doSomething", httpMethod = "get")
public ResponseMessage ReturnSomething(#Named("tokenId") String tokenId, User user) throws UnauthorizedException, BadRequestException, InternalServerErrorException, FirebaseAuthException
{
if (user == null)
...
In production, when the URL is called from an Angular application on Firebase that passes the token in the URL, user is correctly created. I don't fully understand how the User is created from the token, I only know that it somehow happens "automatically" as part of Firebase integration with Google Cloud.
I want to debug the API locally by using Debug As > App Engine from inside Eclipse. When I do this however, and call the API from my local Angular application running using Firebase serve, the token is correctly passed to my locally running API, however user is always null.
#ApiMethod(path = "myPath/{tokenId}/doSomething", httpMethod = "get")
public ResponseMessage ReturnSomething(#Named("tokenId") String tokenId, User user) throws UnauthorizedException, BadRequestException, InternalServerErrorException, FirebaseAuthException
{
if (user == null)
// this is always null
I suspect this is a problem with my locally running Java API correctly authenticating to Firebase. I've looked at this guide, which suggests that the GOOGLE_APPLICATION_CREDENTIALS property on Windows should be set to the path of the JSON key of the App Engine default service account, which is the normal way to ensure that local access is granted to Google Cloud (and presumably Firebase) resources.
I've added this explicitly (I'd already run gcloud auth application-default login anyway, using the command line) however it's still not working. I just get null for the user and there's no indication of what's going on. I don't want to programatically authenticate as that means altering the API code to authenticate differently during debugging. How do I retrieve a User when debugging locally as App Engine?
UPDATE
I've realised that although the tokenId in the URL is present, I'm getting the following error when the API is called:
WARNING: Authentication failed: com.google.api.auth.UnauthenticatedException: No auth token is contained in the HTTP request
The tokenId value in the code below is a valid value, so I'm not sure why I'm getting this message:
#ApiMethod(path = "myPath/{tokenId}/doSomething", httpMethod = "get")
public ResponseMessage ReturnSomething(#Named("tokenId") String tokenId, User user)
I discovered that this was actually a problem with the Auth0 library that's being used in Angular to support authenticated HTTP requests to the Java API. The Auth0 library is used to inject the auth token into the Bearer of the request header whenever an Angular http.get is called from the Angular application. Creation of the User depends on this property being present in the HTTP header, with its value set to the value of the auth token.
I fixed this by altering the config for this library. I needed to temporarily whitelist localhost for the port (8080) that the API runs on, to allow Auth0 to inject the token into the HTTP header whenever there is a request to localhost:8080
const jwtConf: JwtModuleOptions = {
config: {
tokenGetter: getToken,
whitelistedDomains: ['localhost:8080']
}
};
Related
I am new using Azure Graph Rest API Java using this repo.
My aim is to list all of the users in the AAD tenant
So far I was only able to get to this:
List<String> scopes= Arrays.asList("https://graph.microsoft.com/User.Read.All");
AzureProfile profile = new AzureProfile(tenantId, subscriptionId, AzureEnvironment.AZURE);
final ClientSecretCredential credential = new ClientSecretCredentialBuilder()
.clientId(clientId)
.clientSecret(clientSecret)
.tenantId(tenantId)
//.httpClient(client)
.authorityHost(profile.getEnvironment().getActiveDirectoryEndpoint())
.build();
TokenCredentialAuthProvider tokenCredentialAuthProvider = new TokenCredentialAuthProvider(scopes, credential);
GraphServiceClient<Request> graphClient =
GraphServiceClient
.builder()
.authenticationProvider(tokenCredentialAuthProvider)
.buildClient();
UserCollectionPage users = graphClient.users()
.buildRequest()
.get();
for(User user: users.getCurrentPage()){
System.out.println(user.displayName);
System.out.println(user.id);
System.out.println(user.userPrincipalName);
}
However, I run into this error instead:
Caused by: java.io.IOException:
java.util.concurrent.ExecutionException:
com.microsoft.aad.msal4j.MsalServiceException:
AADSTS1002012: The
provided value for scope https://graph.microsoft.com/User.Read.All
openid profile offline_access is not valid. Client credential flows
must have a scope value with /.default suffixed to the resource
identifier (application ID URI).
It seems the Scope that I have used is wrong/insufficient, but I am not too sure what should I use the scope with. Any idea?
It is written in the documentation that:
Client credentials requests in your client service must include
scope={resource}/.default. Here, {resource} is the web API that your
app intends to call, and wishes to obtain an access token for. Issuing
a client credentials request by using individual application
permissions (roles) is not supported. All the app roles (application
permissions) that have been granted for that web API are included in
the returned access token.
The Client Credential flow is best suited for situations where you have a Deamon App that will have to authenticate and get access to some kind of a resource through a Non-Interactive way, which in sequence means that the permissions for this Deamon App have been configured and consented from a step done prior to the auth request.
The /.default scope can be translated as the request of the Background App that runs unattended, to get the bulk of the permissions that it has been configured with and access the resource that it asks.
In plain english, the use of the above scope in the Client Credentials flow is a convention that has to be implemented always when this flow is chosen :P.
I tried to reproduce the same in my environment via Postman and got below results:
I registered one Azure AD application and added API permissions like below:
When I tried to generate access token with same scope as you via Postman using client credentials flow, I got same error as below:
POST https://login.microsoftonline.com/<tenantID>/oauth2/v2.0/token
grant_type:client_credentials
client_id: <appID>
client_secret: <secret_value>
scope: https://graph.microsoft.com/User.Read.All openid profile offline_access
Response:
To resolve the above error, you must change your scope to https://graph.microsoft.com/.default if you are using client credentials flow.
After changing the scope, I'm able to generate access token successfully like below:
POST https://login.microsoftonline.com/<tenantID>/oauth2/v2.0/token
grant_type:client_credentials
client_id: <appID>
client_secret: <secret_value>
scope: https://graph.microsoft.com/.default
Response:
When I used the above token to call below Graph query, I got the list of users with display name, id and user principal name successfully like below:
GET https://graph.microsoft.com/v1.0/users?$select=displayName,id,userPrincipalName
Response:
In your case, change scope value in your code like below:
List<String> scopes= Arrays.asList("https://graph.microsoft.com/.default");
I am trying to implement Keycloak as an IAM, the Problem that I have is, that I need to authenticate the user (already working) but also authorize him. The authorization should be accomplished through keycloak directly, but the security information (like roles, etc.) is available over an REST interface externally.
The way it is working now goes as followed:
authentication request (default)
"authorization" request → keycloak server (with extra form param)
keycloak server → CustomProtocolMapper (calls external REST interface and adds claims to Token)
Token → frontend client
This worked until I used a refresh token to refresh the ID Token. The Cookie that is used to authenticate the user is not sent to the keycloak server, because of security reasons (Cookie labeled as "Secure" but connection over HTTP). To fix this I upgrade my keycloak server to use HTTPS/TLS and now i am getting errors because the "HttpRequest" is no longer available. Any ideas on how to get the Request Body of an HTTPS Request inside a CustomProtocolMapper? I know that the Authenticator Providers has access to it, but i dont know/ didnt find anyway to add claims to the Token inside it.
#Override
protected void setClaim(IDToken token, ProtocolMapperModel mappingModel, UserSessionModel userSession, KeycloakSession keycloakSession,
ClientSessionContext clientContext) {
String contextParamName = mappingModel.getConfig().get(CONTEXT_PARAMETER);
// worked with http
HttpRequest request = keycloakSession.getContext().getContextObject(HttpRequest.class);
String contextId = request.getFormParameters().getFirst("activeContext");
LOGGER.warn("activeContext: " + contextId);
}
Thanks in advance,
best regards
I followed this guide
For local testing and webhook processing, I used https://webhook.site
I managed to get messages about file changes (google sheets)
Next, I tried to configure the local endpoint of my application to handle the webhook
From the documentation https://support.google.com/googleapi/answer/7072069?hl=en
An address property string set to the URL that listens and responds to
notifications for this notification channel. This is your Webhook
callback URL, and it must use HTTPS.
Also for local testing I used https://ngrok.com/
#PostMapping("/notifications")
#AnonymousAllowed
public ResponseEntity<Void> webHookHandler(HttpServletRequest request) {
String headerGoogChanged = request.getHeader("x-goog-changed");
if (!ObjectUtils.isEmpty(headerGoogChanged) && headerGoogChanged.contains("content")) {
service.parseDashboardAndSave(view.getGrid(), sheetsService.readSheetValuesBatch());
sheetsService.writeSheetValuesBatch(service.getKeyWordDashboards());
log.info("Push notification processed: {}", request);
}
return ResponseEntity.ok().build();
}
But I don't get push notifications
At the same time, calling endpoints https://localhost:8080/notifications and https://xxxxxxeu.ngrok.io/notifications through postman will work
I heard that you need to pass domain verification and also have an SSL certificate
I found that now there is no need to confirm the domain in this documentation
Can some one help me to setup Oauth 2 Authorisation server Vert.x (3.3.0).I dont find any documentation related to it.
I found vertx-auth-oauth2 this vert.x module but I guess it will be useful if Authorisation server is different
e.g
The following code snippet is from vert.x documentation
OAuth2Auth oauth2 = OAuth2Auth.create(vertx, OAuth2FlowType.AUTH_CODE, new OAuth2ClientOptions()
.setClientID("YOUR_CLIENT_ID")
.setClientSecret("YOUR_CLIENT_SECRET")
.setSite("https://github.com/login")
.setTokenPath("/oauth/access_token")
.setAuthorizationPath("/oauth/authorize")
);
// when there is a need to access a protected resource or call a protected method,
// call the authZ url for a challenge
String authorization_uri = oauth2.authorizeURL(new JsonObject()
.put("redirect_uri", "http://localhost:8080/callback")
.put("scope", "notifications")
.put("state", "3(#0/!~"));
// when working with web application use the above string as a redirect url
// in this case GitHub will call you back in the callback uri one should now complete the handshake as:
String code = "xxxxxxxxxxxxxxxxxxxxxxxx"; // the code is provided as a url parameter by github callback call
oauth2.getToken(new JsonObject().put("code", code).put("redirect_uri", "http://localhost:8080/callback"), res -> {
if (res.failed()) {
// error, the code provided is not valid
} else {
// save the token and continue...
}
});
It is using Github as Authorisation server.I am curious to know how to implement Authorisation server in vert.x ,i know spring security provides this feature i.e Oauth2Server and OAuth2Client.
Vert.x OAuth2 is just a OAuth2Client, there is no server implementation so you cannot get it from the Vert.x Project itself.
Vert.x OAuth2 supports the following flows:
Authorization Code Flow (for apps with servers that can store persistent information).
Password Credentials Flow (when previous flow can’t be used or during development).
Client Credentials Flow (the client can request an access token using only its client credentials)
I have a web application that I deploy using JBoss 5.2. In order for a user to use the application, he/she must authenticate with an LDAP server (using simple authentication) with a username and password. This is all done through setting up the login-config.xml for JBoss and providing a <login-module> with our implementation.
The problem comes in here: After having logged in, I have a scenario that requires the user to provide a username & password when a particular action is performed (which I will also authenticate with the LDAP server). I want to be able to reuse the same mechanism that I use for authenticating the user into the web application.
My form to log in to the application posts to j_security_check so in accordance with this, I was trying to send a request to j_security_check but JBOSS returns a 404. From reading around a bit, I've gathered j_security_check cannot be accessed by any arbitrary request and must be in response to a challenged request to a secured resource.
So then, how can I authenticate the second set of credentials the user has provided with the same LDAP server?
EDIT:
To clarify, the question is how to send the user's credential inputs to the LDAP server for authentication. Grabbing the input from the user, etc. is all done. All that is left is to take this input and send it to the LDAP server and get the response (which is where I am stuck).
If it helps to mention, the login to the web application uses a custom class that extends UsernamePasswordLoginModule.
So, after lots of research, I ended up finding a solution for JBoss environments (which is what I'm using).
Once you capture the user's credentials, you send them to your server via a POST/GET and your server can perform the following to use whatever authentication policy you have configured (in login-config.xml) to verify the credentials:
WebAuthentication webAuthentication = new WebAuthentication();
boolean success = webAuthentication.login(username, password);
To expand on this, I was also able to check the user's role/group via the HttpServletRequest (which is passed into my server-side handler):
boolean userIsInRole = servletRequest.isUserInRole("nameOfGroup")
The spring security documentation explains it
Wanted to add another answer for JBoss 6.2+, where WebAuthentication no longer exists.
I've used the creation of a LoginContext to achieve the same result:
String SECURITY_DOMAIN_NAME = "ssd"; // the security domain's name from standalone.xml
String username = "user";
String password = "password";
LoginContext lc = null;
try {
lc = new LoginContext(SECURITY_DOMAIN_NAME, new UsernamePasswordHandler(username, password.toCharArray()));
lc.login();
// successful login
} catch (LoginException loginException) {
// failed login
}
And the use uf lc.getSubject().getPrincipals() to verify roles.