What JWT validation do I need to do on an Identity Server Client? - identityserver3

I configured my identity server client like this in Startup.cs
app.UseJwtBearerAuthentication(options =>
{
options.Authority = Configuration["Urls:IdentityServer"];
options.RequireHttpsMetadata = false;
options.Audience = Configuration["Urls:IdentityServer"] + "/resources";
options.AutomaticAuthenticate = true;
}
will this take of all the recommended JWT validations(signature, nonce etc) or do I have to write any validations of my own?

You should require HTTPS on the metadata in production.
In addition to the JWT middleware, you will need to do scope validation.

Related

Keycloak java client 403 when retrieving role detail

I'm working with keycloak 8.0.1 and it's java client keycloak-admin-client library.
this is my Keycloak config
public Keycloak keycloakClient(AdapterConfig config) {
return KeycloakBuilder.builder()
.clientId(config.getResource())
.clientSecret((String) config.getCredentials().get(CredentialRepresentation.SECRET))
.grantType(OAuth2Constants.CLIENT_CREDENTIALS)
.realm(config.getRealm())
.serverUrl(config.getAuthServerUrl())
.build();
}
And with this code I'd like to create user and assign him a role
final UserRepresentation user = createUserRepresentation(data);
final UsersResource userResource = getRealmResource().users();
try (Response response = userResource.create(user)) {
if (response.getStatusInfo().getFamily().equals(Response.Status.Family.SUCCESSFUL)) {
final String userId = response.getLocation().getPath().replaceAll(".*/([^/]+)$", "$1");
final RolesResource rolesResource = getRealmResource().roles();
final RoleResource roleResource = rolesResource.get(data.getRole().getRemoteName());
final RoleRepresentation role = roleResource.toRepresentation();
userResource.get(userId).roles().realmLevel().add(Collections.singletonList(role));
return userId;
} else {
throw new IllegalStateException("Unable to create user " + response.getStatusInfo().getReasonPhrase());
}
}
however it fails on line final RoleRepresentation role = roleResource.toRepresentation(); with message javax.ws.rs.ForbiddenException: HTTP 403 Forbidden.
I don't understand why am I getting this error, because my client has assigned all roles from realm-management client
create-client
impersonation
manage-authorization
manage-clients
manage-events
manage-identity-providers
manage-realm
manage-users
query-clients
query-groups
query-realms
query-users
realm-admin
view-authorization
view-clients
view-events
view-identity-providers
view-realm
view-users
Is there some config which am I missing or is it a bug?
Thanks
I just have the same problem here, while I'm trying to assign roles to an existing user using a service client (using client credentials).
The solution:
Go to Clients > Select "your" client > Go to "Service Account Roles" Tab > Select Client Roles : "realm-management" and add "view-realm" into the assigned roles.
That's it :)

getting NoAuthorization Header Missing Exception while using flask-jwt-extended

When I try this example and if the jet token is not provided by header I get error:
{
"msg": "Missing cookie \"access_token_cookie\""
}
example:
from flask import Flask, jsonify, request
from flask_jwt_extended import (
JWTManager, jwt_required, create_access_token,
jwt_refresh_token_required, create_refresh_token,
get_jwt_identity, set_access_cookies,
set_refresh_cookies, unset_jwt_cookies
)
from flask_jwt_extended.config import config
# NOTE: This is just a basic example of how to enable cookies. This is
# vulnerable to CSRF attacks, and should not be used as is. See
# csrf_protection_with_cookies.py for a more complete example!
app = Flask(__name__)
# Configure application to store JWTs in cookies. Whenever you make
# a request to a protected endpoint, you will need to send in the
# access or refresh JWT via a cookie.
app.config['JWT_TOKEN_LOCATION'] = ['cookies']
# Set the cookie paths, so that you are only sending your access token
# cookie to the access endpoints, and only sending your refresh token
# to the refresh endpoint. Technically this is optional, but it is in
# your best interest to not send additional cookies in the request if
# they aren't needed.
app.config['JWT_ACCESS_COOKIE_PATH'] = '/api/'
app.config['JWT_REFRESH_COOKIE_PATH'] = '/token/refresh'
# Disable CSRF protection for this example. In almost every case,
# this is a bad idea. See examples/csrf_protection_with_cookies.py
# for how safely store JWTs in cookies
app.config['JWT_COOKIE_CSRF_PROTECT'] = False
# Set the secret key to sign the JWTs with
app.config['JWT_SECRET_KEY'] = 'super-secret' # Change this!
jwt = JWTManager(app)
# Use the set_access_cookie() and set_refresh_cookie() on a response
# object to set the JWTs in the response cookies. You can configure
# the cookie names and other settings via various app.config options
#app.route('/token/auth', methods=['POST'])
def login():
# username = request.json.get('username', None)
# password = request.json.get('password', None)
# if username != 'test' or password != 'test':
# return jsonify({'login': False}), 401
# print dir(config)
# Create the tokens we will be sending back to the user
access_token = create_access_token(identity="test")
refresh_token = create_refresh_token(identity="test")
# Set the JWT cookies in the response
resp = jsonify({'login': True, "cookie_key": config.access_cookie_name, "cooke_value": access_token})
set_access_cookies(resp, access_token)
set_refresh_cookies(resp, refresh_token)
return resp, 200
# Same thing as login here, except we are only setting a new cookie
# for the access token.
#app.route('/token/refresh', methods=['POST'])
#jwt_refresh_token_required
def refresh():
# Create the new access token
current_user = get_jwt_identity()
access_token = create_access_token(identity=current_user)
# Set the JWT access cookie in the response
resp = jsonify({'refresh': True})
set_access_cookies(resp, access_token)
return resp, 200
# Because the JWTs are stored in an httponly cookie now, we cannot
# log the user out by simply deleting the cookie in the frontend.
# We need the backend to send us a response to delete the cookies
# in order to logout. unset_jwt_cookies is a helper function to
# do just that.
#app.route('/token/remove', methods=['POST'])
def logout():
resp = jsonify({'logout': True})
unset_jwt_cookies(resp)
return resp, 200
# We do not need to make any changes to our protected endpoints. They
# will all still function the exact same as they do when sending the
# JWT in via a header instead of a cookie
#app.route('/api/example', methods=['GET'])
#jwt_required
def protected():
username = get_jwt_identity()
return jsonify({'hello': 'from {}'.format(username)}), 200
if __name__ == '__main__':
app.run(debug=True)
But in my office I have similar setup except I am not calling
username = get_jwt_identity()
I get NoAuthorization exception get raised.
how does this work ...
It's mean you not login and flask-jwt can't find any token on your cookies.
Do you login before call this resource?
check your cookie that returned from app.
In my case it was CORS error, I was using a different api address from the website

Is it possible to secure a ColdFusion 11 REST Service with HTTP BASIC Authentication?

I am setting up a simple REST Service in ColdFusion 11. The web server is IIS 8.5 on Windows Server 2012R2.
This REST Service needs to be secured to prevent unauthorized users from accessing/writing data. For the time being, there will be only one authorized user, so I want to keep authentication/authorization as simple as possible. My initial thought is to use HTTP BASIC Authentication.
Here's the setup for the REST Service:
Source Directory: C:\web\site1\remoteapi\
REST path: inventory
To implement this, I configured the source directory of the REST Service in IIS to authorize only one user, disable Anonymous authentication, and enable Basic authentication.
When I call the source directory directly in a browser (i.e. http://site1/remoteapi/inventory.cfc?method=read), I am presented with the Basic authentication dialog.
However, when I attempt to request the REST path (http://site1/rest/inventory/), I am not challenged at all.
How can I implement HTTP BASIC authentication on the REST path?
So, due to the need to get this done without much delay, I went ahead and using some principles from Ben Nadel's website, I wrote my own authentication into the onRequestStart() method of the REST Service's Application.cfc. Here is the basic code, though it uses hard-coded values in the VARIABLES scope to validate the username and password and also does not include any actual "authorization" setting:
public boolean function onRequestStart(required string targetPage) {
LOCAL.Response = SUPER.onRequestStart(ARGUMENTS.targetpage);
if (!StructKeyExists(GetHTTPRequestData().Headers, "Authorization")) {
cfheader(
name="WWW-Authenticate",
value="Basic realm=""REST API Access"""
);
LOCAL.RESTResponse = {
status = 401,
content = {Message = "Unauthorized"}
};
restSetResponse(LOCAL.RESTResponse);
}
else {
LOCAL.IsAuthenticated = true;
LOCAL.EncodedCredentials =
GetToken( GetHTTPRequestData().Headers.Authorization, 2, " " );
// Credential string is not Base64
if ( !ArrayLen(
REMatch(
"^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$",
LOCAL.EncodedCredentials
)
)
) {
LOCAL.IsAuthenticated = false;
}
else {
// Convert Base64 to String
LOCAL.Credentials =
ToString(ToBinary( LOCAL.EncodedCredentials ));
LOCAL.Username = GetToken( LOCAL.Credentials, 1, ":" );
LOCAL.Password = GetToken( LOCAL.Credentials, 2, ":" );
if ( LOCAL.Username != VARIABLES.CREDENTIALS.Username
|| LOCAL.Password != VARIABLES.CREDENTIALS.Password
) {
LOCAL.IsAuthenticated = false;
}
}
if (!LOCAL.IsAuthenticated) {
LOCAL.Response = {
status = 403,
content = {Message = "Forbidden"}
};
restSetResponse(LOCAL.Response);
}
}
return LOCAL.Response;
}

Performing http web request to a server requiring SAML authentication

I have simple app that is trying to do a http web request to a server that requires SAML authentication. Authenticated users will get a http response header with a special token, which is what I need to ultimately get.
My app is .net based and does a pretty simple http web request. It does the request then parses the response header. I later traverse the header for the specific token I need:
...
try
{
WindowsIdentity identity = HttpContext.User.Identity as WindowsIdentity;
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
req.UseDefaultCredentials = true;
req.AllowAutoRedirect = true;
req.Timeout = 30000;
HttpWebResponse response = (HttpWebResponse)req.GetResponse();
if (response == null)
{
throw new Exception("No HTTP Response");
}
StringBuilder sb = new StringBuilder();
Byte[] buffer = new byte[8192];
Stream rStream = response.GetResponseStream();
int count = 1;
do
{
count = rStream.Read(buffer, 0, buffer.Length);
if (count != 0)
{
sb.Append(Encoding.UTF8.GetString(buffer, 0, count));
}
} while (count > 0);
...
The problem is that the server I'm requesting requires SAML authentication. It redirects to an ADFS server upon request. My app server currently uses kerberos authentication but I can enable it to do SAML as well. Both servers use the same IdP (ADFS) and are in the same enterprise.
My question is - since my app can also do SAML on the same IdP, is there anyway I could get the necessary claims to connect directly into the destination server?

Apache Wink Client - Test a REST service using form auth

I am trying to use the Wink RestClient to do functional testing on a Rest service endpoint. I use mocks for unit testing but I'd like to functionally test it as an endpoint consumer.
I understand some will object to me calling it a REST endpoint while using form-based auth but that is the current architecture I have.
The majority of the resources I want to test are protected resources and the application (running on Tomcat6) is protected by form authentication. (as in the below web.xml snippet).
What I've tried so far is to make an initial call to an unprotected resource, to obtain the set-cookie header, that contains JSESSIONID, and use that JSESSIONID in the header ( via Resource.cookie() ) in subsequent requests but that does not yield fruit.
web.xml
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/login.html</form-login-page>
<form-error-page>/login.html?failure=true</form-error-page>
</form-login-config>
</login-config>
My Wink RestClient code looks like below. All responses are 200, but two things I notice are that the response from the call to /j_security_check/ does not include the jsessionid cookie, and the call to the protected resource said I had a signin failure. The payload for the call to j_security_check was captured directly from a previous successful browser request intercepted.
ClientConfig config = new ClientConfig();
config.setBypassHostnameVerification(true);
RestClient restClient = new RestClient(config);
Resource unprotectedResource = restClient.resource( BASE_URL + "/");
unprotectedResource.header( "Accept", "*/*" );
ClientResponse clientResponse = unprotectedResource.get();
String response = clientResponse.getEntity(String.class);
// get jSession ID
String jSessionId = clientResponse.getHeaders().get("set-cookie").get(0);
jSessionId = jSessionId.split(";")[0];
System.out.println(jSessionId);
// create a request to login via j_security_check
Resource loginResource = restClient.resource(BASE_URL + "/j_security_check/");
loginResource.accept("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
loginResource.header("referer", "http://localhost:8080/contextroot/");
loginResource.cookie( jSessionId );
loginResource.header("Connection", "keep-alive");
loginResource.header("Content-Type", "application/x-www-form-urlencoded");
loginResource.header("Content-Length", "41");
ClientResponse loginResponse = loginResource.post("j_username=*****&j_password=*************");
/* the loginResponse, as this point, does not have the jsessionid cookie, my browser client does */
Resource protectedResource = restClient.resource(BASE_URL + "/protected/test/");
systemResource.accept("application/json");
systemResource.cookie( jSessionId );
ClientResponse systemResponse = systemResource.get();
response = clientResponse.getEntity(String.class);
System.out.println(response);
Any thoughts or experience with using the Wink RestClient to exercise form-auth-protected resources would be greatly appreciated. I suppose I'd entertain other frameworks, I have heard of REST-Assured and others, but since the application uses Wink and the RestClient seems to provide me with what I need, I figured I'd stick with it.
Found the problem, and the solution
j_security_check was responding to my POST request (to authenticate), with a #302/redirect. That was being followed by the wink RestClient, but my JSESSIONID cookie was not being appended to it. That was causing the response (from the redirected URL) to contain a set-cookie header, with a new header. My subsequent calls, into which I inserted the JSESSIONID from the first call, failed, because that cookie was expired. All I needed to do was instruct the RestClient to NOT follow redirects. If the redirect were necessary, I would construct it on my own, containing the appropriate cookie.
Chromium and Firefox carry the cookie from the original request to the redirected request so it's all good.
Here is some code that worked for me, using JUnit4, RestClient from the Apache Wink project (and a Jackson ObjectMapper)
#Test
public void testGenerateZipEntryName() throws JsonGenerationException, JsonMappingException, IOException
{
final ObjectMapper mapper = new ObjectMapper();
final String BASE_URL = "http://localhost:8080/rest";
// Configure the Rest client
ClientConfig config = new ClientConfig();
config.proxyHost("localhost"); // helpful when sniffing traffic
config.proxyPort(50080); // helpful when sniffing traffic
config.followRedirects(false); // This is KEY for form auth
RestClient restClient = new RestClient(config);
// Get an unprotected resource -- to get a JSESSIONID
Resource resource = restClient.resource( BASE_URL + "/");
resource.header( "Accept", "*/*" );
ClientResponse response = resource.get();
// extract the jSession ID, in a brittle and ugly way
String jSessId = response.getHeaders().get("set-cookie").get(0).split(";")[0].split("=")[1];
// Get the login resource *j_security_check*
resource = restClient.resource(BASE_URL + "/j_security_check");
resource.cookie("j_username_tmp=admin; j_password_tmp=; JSESSIONID=" + jSessId);
resource.header("Content-Type", "application/x-www-form-urlencoded");
resource.header("Content-Length", "41");
// Verify that login resource redirects us
response = resource.post("j_username=admin&j_password=***********");
assertTrue( response.getStatusCode() == 302 );
// Grab a public resource
resource = restClient.resource(BASE_URL + "/");
resource.cookie("j_username_tmp=admin; j_password_tmp=; JSESSIONID=" + jSessId);
response = resource.get();
// verify status of response
assertTrue( response.getStatusCode() == 200 );
// Grab a protected resource
resource = restClient.resource(BASE_URL + "/rest/system");
resource.cookie("j_username_tmp=admin; j_password_tmp=; JSESSIONID=" + jSessId);
// Verify resource returned OK
response = resource.contentType("application/json").accept("*/*").get();
assertTrue( response.getStatusCode() == 200 );
// Deserialize body of protected response into domain object for further testing
MyObj myObj = mapper.readValue(response.getEntity(String.class), MyObj.class );
assertTrue( myObj.customerArchived() == false );
}