Should I explicitly verify Keycloak token or this is done by Keycloak adapter? - spring-boot

There is a Spring-boot REST API, that needs to be secured by Keycloak, the application is using Keycloak-Spring-Security adapter (6.0.1).
A call to an API endpoint, carries along the bearer token, obtained from Keycloak (currently through postman).
I'm able to perform a successful REST endpoint call, but other thing is troubling me - should I explicitly verify the token against the public key?
1 - Is the adapter performing verification of the token against the public key, or should I implement it?
2 - If the adapter is doing this - can you point out in which classes is this getting done?
3 - If - not - how should this verification be implemented? Are there any Keycloak libraries that I can use to verify the token?

Well, after a few days of searching the web for answer - I got it.
I looked into the code of Keycloak-spring-security-adapter and found it.
First of all I got the logging lever for keycloak to DEBUG:
logging.level.org.keycloak=DEBUG
Then I tried to access my endpoint with bad token (I expected that this is going to produce an exception, i.e. more visible trace; and it did):
2019-10-17 10:18:57,905 | 30860 | http-nio-8081-exec-2 | | | | | DEBUG | | org.keycloak.adapters.PreAuthActionsHandler | adminRequest http://localhost:8081/error
2019-10-17 10:18:57,906 | 30860 | http-nio-8081-exec-2 | | | | | DEBUG | | org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter | Request is to process authentication
2019-10-17 10:18:57,906 | 30860 | http-nio-8081-exec-2 | | | | | DEBUG | | org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter | Attempting Keycloak authentication
2019-10-17 10:18:57,906 | 30860 | http-nio-8081-exec-2 | | | | | DEBUG | | org.keycloak.adapters.BearerTokenRequestAuthenticator | Found [1] values in authorization header, selecting the first value for Bearer.
2019-10-17 10:18:57,906 | 30860 | http-nio-8081-exec-2 | | | | | DEBUG | | org.keycloak.adapters.BearerTokenRequestAuthenticator | Verifying access_token
2019-10-17 10:18:57,908 | 30860 | http-nio-8081-exec-2 | | | | | DEBUG | | org.keycloak.adapters.BearerTokenRequestAuthenticator | Failed to verify token
2019-10-17 10:18:57,908 | 30860 | http-nio-8081-exec-2 | | | | | DEBUG | | org.keycloak.adapters.RequestAuthenticator | Bearer FAILED
2019-10-17 10:18:57,908 | 30860 | http-nio-8081-exec-2 | | | | | DEBUG | | org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter | Auth outcome: FAILED
2019-10-17 10:18:57,925 | 30860 | http-nio-8081-exec-2 | | | | | DEBUG | | org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter | Authentication request failed: org.keycloak.adapters.springsecurity.KeycloakAuthenticationException: Invalid authorization header, see WWW-Authenticate header for details org.keycloak.adapters.springsecurity.KeycloakAuthenticationException: Invalid authorization header, see WWW-Authenticate header for details
at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter.attemptAuthentication(KeycloakAuthenticationProcessingFilter.java:158)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
.....
From then on it is clear that the token is being verified, if you look into the classes that take part, you'll see that it is getting verified against the public key in certain situations.
Classes that take part in this authentication & verification are, in my case (bearer-only) are:
org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter
org.keycloak.adapters.BearerTokenRequestAuthenticator
Hopefully this can help other people like me to find their way in Keycloak.

Related

OAauth2 Authorization Server - external login page and redirect after login

I am trying to integrate Spring Auth Server with an existing authentication provider, IBM WebSeal in the context of an OICD flow.
Basically, I want Spring Auth Server to use Webseal login page to authenticate a user (coming from a SPA/front-end app) and then return a JWT token to the front-end app.
On successful authentication, WebSeal redirects to a configurable URL adding a header to the request. This header contains the actual username and signals that the user is authenticated.
I was able to implement the flow and have Spring Auth Server use the external login page, but I don't understand to which URL should WebSeal redirect. Do I need to create an explicit end-point (such as /authenticated)?
It seems that the OAUTH2 spec doesn't define an explicit endpoint for this particular case.
Adding diagram for clarity:
+----------------+ +------------------+
| | | |
| | | |
| FRONT END APP | | BACK-END APP |
| | | (SPRING BOOT) |
| | | |
| | | |
+---|----|-------+ +------------------+
| |
4 - /oauth2/token | | 1 - /oauth2/authorize?
| |
| |
| |
+---|----|-------+ +----------------+
| | 3 - send header | |
| SPRING -------------------- |
| AUTH | | WEBSEAL |
| SERVER -------------------| |
| | 2 - show form | |
| | +----------------+
+----------------+
Thanks!

SOLVED Laravel website returns "Error 404" for GET requests

So I got a template of a Flutter app that retrieves all its data from a website using HTTP get requests.
I have the following method that gets the list of resturaunts:
Future<Stream<Restaurant>> getNearRestaurants(LocationData myLocation, LocationData areaLocation) async {
String _nearParams = '';
String _orderLimitParam = '';
if (myLocation != null && areaLocation != null) {
_orderLimitParam = 'orderBy=area&limit=5';
_nearParams = '&myLon=${myLocation.longitude}&myLat=${myLocation.latitude}&areaLon=${areaLocation.longitude}&areaLat=${areaLocation.latitude}';
}
final String url = '${GlobalConfiguration().getString('api_base_url')}restaurants?$_nearParams&$_orderLimitParam';
final client = new http.Client();
final streamedRest = await client.send(http.Request('get', Uri.parse(url)));
return streamedRest.stream.transform(utf8.decoder).transform(json.decoder).map((data) => Helper.getData(data)).expand((data) => (data as List)).map((data) {
return Restaurant.fromJSON(data);
});
}
However when I swap the template's url variable for my own website, the app gets stuck and streamRest returns with an error 404 page.
Tried Solutions:
I surrounded it with a try/catch block and it gave me no exceptions.
I also installed postman and checked my website with the GET statement for the same list of restaurants I try to retrieve in the flutter code posted above and see this: Postman GET screenshot
Its as if my website cannot route to the specific pages in my API folder. But they are all defined in api.php.
Update 1:
My web.php looks like this https://pastebin.com/QRG300uL. It seems to be similar to what was suggested below
Update 2:
I ran php artisan route::list and it showed that all the routes seem to be there:
| | POST | api/restaurant_reviews | restaurant_reviews.store | App\Http\Controllers\API\RestaurantReviewAPIController#store | api |
| | GET|HEAD | api/restaurant_reviews | restaurant_reviews.index | App\Http\Controllers\API\RestaurantReviewAPIController#index | api |
| | GET|HEAD | api/restaurant_reviews/create | restaurant_reviews.create | App\Http\Controllers\API\RestaurantReviewAPIController#create | api |
| | DELETE | api/restaurant_reviews/{restaurant_review} | restaurant_reviews.destroy | App\Http\Controllers\API\RestaurantReviewAPIController#destroy | api |
| | GET|HEAD | api/restaurant_reviews/{restaurant_review} | restaurant_reviews.show | App\Http\Controllers\API\RestaurantReviewAPIController#show | api |
| | PUT|PATCH | api/restaurant_reviews/{restaurant_review} | restaurant_reviews.update | App\Http\Controllers\API\RestaurantReviewAPIController#update | api |
| | GET|HEAD | api/restaurant_reviews/{restaurant_review}/edit | restaurant_reviews.edit | App\Http\Controllers\API\RestaurantReviewAPIController#edit | api |
| | GET|HEAD | api/restaurants | restaurants.index | App\Http\Controllers\API\RestaurantAPIController#index | api |
| | POST | api/restaurants | restaurants.store | App\Http\Controllers\API\RestaurantAPIController#store | api |
| | GET|HEAD | api/restaurants/create | restaurants.create | App\Http\Controllers\API\RestaurantAPIController#create | api |
| | GET|HEAD | api/restaurants/{restaurant} | restaurants.show | App\Http\Controllers\API\RestaurantAPIController#show | api |
| | DELETE | api/restaurants/{restaurant} | restaurants.destroy | App\Http\Controllers\API\RestaurantAPIController#destroy | api |
| | PUT|PATCH | api/restaurants/{restaurant} | restaurants.update | App\Http\Controllers\API\RestaurantAPIController#update | api |
| | GET|HEAD | api/restaurants/{restaurant}/edit | restaurants.edit | App\Http\Controllers\API\RestaurantAPIController#edit | api |
| | POST | api/send_reset_link_email | | App\Http\Controllers\API\UserAPIController#sendResetLinkEmail | api |
| | GET|HEAD | api/settings | | App\Http\Controllers\API\UserAPIController#settings | api |
Solution:
This worked for me after changing alot of things, I changed my GET request url from "www.domain.com/api/resturants" to "www.domain.com/public/api/resturants"
Well i don't know about your flutter code for i use different methods in retrieving data from api but about the routes i suggest you do like me
in web.php the route file
//Api routes
Route::get('/company/api/fetch', 'ApiController#fetch_companies');
my api controller
public function fetch_companies()
{
$companies = Companies::all();
return response()->json($companies);
}
this way you will get the data passed to the route /company/api/fetch (you can modify that as you want) and when a get request enter this page it will return json
and for the request handling in flutter side i suggest you make your functions and classes as it is in the documentations
Note: that the flutter solution that i suggested may not work with your case for you are using Stream which is different than this type of requests because this type runs only ones while the Stream runs many times and gets data every time it gets new data from the server

Fastlane is getting provisioning profiles with wrong account

This is my output on console:
+---------------+---------------------------------------------------+
| Summary for cert 2.96.1 |
+---------------+---------------------------------------------------+
| development | false |
| force | false |
| username | correctappleid#gmail.com |
| team_id | CSCORRECTTEAMID |
| keychain_path | /Users/bartek/Library/Keychains/login.keychain-db |
| platform | ios |
+---------------+---------------------------------------------------+
[09:01:23]: Starting login with user 'correctappleid#gmail.com'
[09:01:27]: Successfully logged in
[09:01:28]: Certificate 98TLCZS7BR (iOS Distribution) can't be found on your local computer
[09:01:29]: Found the certificate 6K5C2MFHUL (iOS Distribution) which is installed on the local machine. Using this one.
[09:01:30]: Verifying the certificate is properly installed locally...
[09:01:30]: Successfully installed certificate 6K5C2MFHUL
[09:01:30]: Use signing certificate '6K5C2MFHUL' from now on!
[09:01:30]: --------------------------------------
[09:01:30]: --- Step: get_provisioning_profile ---
[09:01:30]: --------------------------------------
+-------------------------------------+-------------------------------------------+
| Summary for sigh 2.96.1 |
+-------------------------------------+-------------------------------------------+
| adhoc | false |
| development | false |
| skip_install | false |
| force | false |
| app_identifier | my.app.identifier |
| username | wrongname#company.com |
| team_id | CSTEAMID |
| ignore_profiles_with_different_name | false |
| cert_id | 6K5C2MFHUL |
| skip_fetch_profiles | false |
| skip_certificate_verification | false |
| platform | ios |
| readonly | false |
+-------------------------------------+-------------------------------------------+
[09:01:30]: Starting login with user 'wrongname#company.com'
-------------------------------------------------------------------------------------
Please provide your Apple Developer Program account credentials
The login information you enter will be stored in your macOS Keychain
You can also pass the password using the `FASTLANE_PASSWORD` environment variable
See more information about it on GitHub: https://github.com/fastlane/fastlane/tree/master/credentials_manager
Why fastlane try to fetch provisionings with wrong user account?
How can I force it to change it?
Where it is defined?
Have you tried setting the user account directly?
https://docs.fastlane.tools/actions/upload_to_app_store/#parameters
https://docs.fastlane.tools/actions/sigh/#parameters

WireMock with multiple hosts and dnsmasq?

I'm working on mocking endpoints for an iOS app that hits over a dozen different HTTPS hosts. Based on my understanding from the WireMock docs and this answer from the maintainer, WireMock is designed to proxy / mock only one host. My current plan is to use dnsmasq to point one host at WireMock at a time.
+----------+ +-------------------+
| | | |
| WireMock +-->Proxy+---> 123.example.com |
| | | |
+----^-----+ +-------------------+
|
| +-------------------+
+-------+ +----+----+ | |
| +---> https://123.example.com +---> | +-----> xyz.example.com |
| | | | | | |
| App +---> https://xyz.example.com +---> dnsmasq +---+ +-------------------+
| | | |
| +---> https://9.different.com +---> +---+ +-------------------+
+-------+ +---------+ | | |
+-----> 9.different.com |
| |
+-------------------+
This seems pretty clunky, is there a better way to mock multiple hosts like this? One of the primary constraints is that these have to be tested over HTTPS and not unencrypted.
You should be able to achieve this by creating stubs that have a host header condition in the request. That way e.g. a request to
GET /hello
Host: firsthost.example.com
And a request to
GET /hello
Host: secondhost.example.com
would match different stubs and there return different responses.

Laravel - Routes GET|HEAD

When I do php artisan routes, the GET request of my app has a |HEAD. What is the purpose of having |HEAD?
Routes.php
+--------+----------------------------------+------------------------------+--------------------------------------+----------------+---------------+
| Domain | URI | Name | Action | Before Filters | After Filters |
+--------+----------------------------------+------------------------------+--------------------------------------+----------------+---------------+
| | GET|HEAD / | home | HomeController#home | | |
| | GET|HEAD user/{username} | profile-user | ProfileController#user | | |
| | GET|HEAD account/change-password | account-change-password | AccountController#getChangePassword | auth | |
| | GET|HEAD asset/encode-file/{id} | encode-file | EncodeController#getEncode | auth | |
| | GET|HEAD asset/edit-file/{id} | edit-file | AssetController#getEdit | auth | |
| | GET|HEAD asset/delete-file/{id} | delete-file | AssetController#deleteDestroy | auth | |
| | GET|HEAD asset/upload-file-form | upload-file-form | AssetController#getUploadCreate | auth | |
| | GET|HEAD asset/library | asset-library | AssetController#getAssetLib | auth | |
| | GET|HEAD account/sign-out | account-sign-out | AccountController#getSignOut | auth | |
| | GET|HEAD account/activate/{code} | account-activate | AccountController#getActivate | guest | |
| | GET|HEAD account/forgot-password | account-forgot-password | AccountController#getForgotPassword | guest | |
| | GET|HEAD account/recover/{code} | account-recover | AccountController#getRecover | guest | |
| | GET|HEAD account/sign-in | account-sign-in | AccountController#getSignIn | guest | |
| | GET|HEAD account/create | account-create | AccountController#getCreate | guest | |
+--------+----------------------------------+------------------------------+--------------------------------------+----------------+---------------+
The HEAD request is almost identical to a GET request, they only differ by a single fundamental aspect: the HEAD response should not include a payload (the actual data).
This makes the HEAD HTTP verb fundamental for managing the validity of your current cached data.
The value for a header field in the response of your HEAD request will warn you if your data is not up-to-date. After that you can make a proper GET request retrieving the updated data.
This can be achieved observing the Content-Length field or the Last-Modified field for example.
When working with large payloads, caching your data and making HEAD requests before the actual GET to check the validity of you current data can save you big money on data consumption.
You will know precisely when to retrieve the full payload.
The big question is: why is Laravel combining HEAD and GET HTTP verbs when you use Route::get()?
You can use Route::match('HEAD') to register your HEAD request, but I find it weird that we don't have Route::head().
From the HTTP RFC:
The HEAD method is identical to GET except that the server MUST NOT return a message-body in the response. The metainformation contained in the HTTP headers in response to a HEAD request SHOULD be identical to the information sent in response to a GET request. This method can be used for obtaining metainformation about the entity implied by the request without transferring the entity-body itself. This method is often used for testing hypertext links for validity, accessibility, and recent modification.
The response to a HEAD request MAY be cacheable in the sense that the information contained in the response MAY be used to update a previously cached entity from that resource. If the new field values indicate that the cached entity differs from the current entity (as would be indicated by a change in Content-Length, Content-MD5, ETag or Last-Modified), then the cache MUST treat the cache entry as stale.
Following function is taken from the Laravel's Illuminate\Routing\Router.php class, when you use Route::get() method to add a route for your site/application, Laravel adds both methods for the url, it means that, these urls registered using getmethod could be accessed using both GET and HEAD HTTP method, and HEAD is just another HTTP verb/method, used for making a HEAD request.
/**
* Register a new GET route with the router.
*
* #param string $uri
* #param \Closure|array|string $action
* #return \Illuminate\Routing\Route
*/
public function get($uri, $action)
{
return $this->addRoute(array('GET', 'HEAD'), $uri, $action);
}

Resources