I'm trying to run a REST project and have inserted securitytoken and session into my header.
But I get an errormessage telling me that a cookie is missing (since my service needs a cookie to run successful).
I have tried to do this with Groovy:
import com.eviware.soapui.impl.wsdl.support.http.HttpClientSupport
def myCookieStore = HttpClientSupport.getHttpClient().getCookieStore()
import org.apache.http.impl.cookie.BasicClientCookie
def myNewCookie = new BasicClientCookie("mycookiename", "mycookievalue")
myNewCookie.version = 1
myNewCookie.domain = "my domain as IP"
myCookieStore.addCookie(myNewCookie)
But its still throwing me the same errormessage.
Are there any solution to inject a cookie as a header in SoapUI 5.0?
I would have like to add this as a comment, but I don't have 50 reputation yet.
Don't know if you are still working on this, but anyway:
Like Rao says it seems like you want to work in a session with a negotiated token. You can go three ways with this in soapui.
Like you propose: create the cookie and the values from scratch. That would be a good use case when you want to test which values are going to pass and which values or combos thereof will return errors or different kinds of messages.
If you want to test anything else then the headers, then you can load a certificate, go to the authentication link and retrieve your tokens and session IDs from the headers in the Set-Cookies as proposed by Rao.
Option number three, my personal favourite when testing other things than headers, is to trust SoapUI to take care of it. You can do this by setting the test case to remember your session. You can set this setting in the testcase settings menu. It is called something the likes of 'Maintain http session'.
Remark: In soapui you can modularize tests. You could for example make a testcase for the authentication in an 'util' test suite. This because you can then disable the util test suite to prevent it from running as a dead-weight test. You can then call to this testcase anywhere to invoke the authentication procedure. For this to work you have to set the settings for the 'Run Testcase' (it is named somehting like that) to 'transport the http session to and from this test case' and, like before, set the parent testcase to 'Maintain HTTP Session'. More info on modularization: https://www.soapui.org/functional-testing/modularizing-your-tests.html.
For the security certificate import, check this smartbear example: https://www.soapui.org/resources/blog/ws-security-settings.html
Related
My login procedure allows admins to select an account that they would like to login-as. For that I can login as that particular user and issue the authorization code, as usual.
Now, what I would like is to extend this setup to allow some other admins to login with "read-only" access. This can easily be mapped to our API by use of certain scopes and removing some other scope.
For the oauth process to work, I do need a way to issue oauth tokens that come with a scope that has been limited server side (less scope than the actual client - server-side because read-only is enforced).
I imagine that I might need to write a new GrantType and probably also have to track state somehow, but I am unclear on how exactly I should use create_authorization_response() in this case.
Ok, after some fiddling around, I found a solution. It essentially creates a custom Oauth2Request (usually client-provided, in our case, modified server-side).
Some rough outline of the code:
from urllib.parse import urlencode, parse_qs, urlparse
# obtain query string as dictionary
query_dict = parse_qs(request.query_string.decode("utf-8"))
# customize scope for this request
query_dict["scope"] = ["profile"]
# We here setup a custom Oauth2Request as we have change the scope in
# the query_dict
req = OAuth2Request(
"POST", request.base_url + "?" + urlencode(query_dict, doseq=True)
)
return authorization.create_authorization_response(grant_user=user, request=req)
We have a FastApi application that is hosted behind a reverse proxy.
The proxy authenticates the user using Kerberos and adds a X-Remote-User HTTP header to the request.
This header is required by the FastApi application. Here is an example route:
#app.get("/user/me")
async def get_user_me(x_remote_user: str = Header(...)):
return {"User": x_remote_user}
The X-Remote-User header is required for the request which is expected behavior.
When we now open the Swagger Ui, the header is documented and when clicking on "Try it out", we can provide the header value.
This behavior is great for development, but in all other cases it is undesired, because that header is provided by the reverse proxy. For instance, we generate clients using OpenAPI Generator and the clients then all require the X-Remote-User parameter in their requests.
Hence, it would be useful to have a configuration that distinguishes between the environments. If we are behind a reverse proxy, then the generated OpenAPI Schema by FastApi should not include the X-Remote-Header, otherwise if we are in development, it should be included.
What I did so far:
I checked the documentation about security and also some source code of these modules, but I was not able to find a solution.
In the documentation, I read the section Behind a Proxy, but nothing there points me to a potential solution.
I also read about Middleware, but again, no solution.
We could change the generated OpenApi schema. I sketched this in my answer below, but this is not a very elegant solution
Does anyone have a good solution to this problem?
We can use APIKeyHeader to remove the X-Remote-User header from the API signature, but still enforcing the header to be present.
from fastapi.security import APIKeyHeader
apiKey = APIKeyHeader(name="X-Remote-User")
#app.get("/user/me")
async def get_user_me(x_remote_user: str = Depends(apiKey)):
return {"User": x_remote_user}
When the header is not present, we get a "403 Forbidden". If it is present, we retrieve the header value.
The Swagger UI now has a button "Authorize" where we can fill-in the value of the X-Remote-User for testing purposes.
One approach is to generate the OpenApi schema as described in the documentation Extending OpenAPI. After the generation, remove the X-Remote-User from the schema. In the configuration could be a flag that the application it is behind a reverse proxy to execute the code conditionally:
from fastapi import FastAPI
from fastapi.openapi.utils import get_openapi
from MyConfig import Config
app = FastAPI()
#app.get("/items/")
async def read_items():
return [{"name": "Foo"}]
if Config.reverse_proxy:
def custom_openapi():
if app.openapi_schema:
return app.openapi_schema
openapi_schema = get_openapi(
title="Custom title",
version="2.5.0",
description="This is a very custom OpenAPI schema",
routes=app.routes,
)
// remove X-Remote-User here
app.openapi_schema = openapi_schema
return app.openapi_schema
app.openapi = custom_openapi
However this is not a very elegant solution, as we need to parse the Json string and remove the different deeply-nested occurrences of the X-Remote-User header everywhere. This is prone to bugs resulting in an invalid schema. Furthermore it could break if new Rest endpoints are added.
A new param will be soon available for Header, Query and other to exclude elements from the openAPI output: include_in_schema=False
Example:
def test(x_forwarded_for: str = Header(None, include_in_schema=False)):
...
Here the patch state: https://github.com/tiangolo/fastapi/pull/3144
I am trying to make a call to an authorization endpoint using OAuth2 with grant type Client Credentials - my call is successful - that is not an issue. However, I, now, want to take the access token that is returned and put it in a variable so I may use it in subsequent calls without having to manually cut-and-paste to my other calls.
When the call returns I see the token I desire to copy in the Access Token field at the bottom of the OAuth2 window (the one shown below that says expires in 42 minutes) AND I see it in the Authorization field on the Timeline tab of the results. I just can't figure out how to get access to it so I may dump it into variable.
The gif on the FAQ goes really fast, and does not provide step by step. Also, I didnt find any answer on YouTube or other websites, so I thought to share step by step for chaining requests on Insomnia.
Create a POST query to obtain your access token. Notice that my access token is returned in the field called "access_token", we will use this in step 3. Your return field may be different.
Create a second GET request for the API that would return the data for you. In my case, I wanted to get all users from a SCIM interface. In the Bearer tab, type in Response => Body Attribute (Insomnia will autofill).
Mouse click on the Request => Body Attribute (the one you just typed in), and select the authentication post in the dropdown "Request" (this is the one you created in step 1), and in the "Filter (JSONPath)" field, type in the $.[attribute name] - where attribute name is the response that returns from authentication call. In my case, it was access_token, see step 1 for yours.
Enjoy!!
Click No Environment > Manage Environments and you will see a base environment in JSON.
Since this is in JSON, create a { "jwt_token": "Response => Body Attribute" }" pair for your token variable. Please note that "Response => Body Attribute" needs to be configured. When you type response, hit space and this option should be available.
Once done choosing "Response => Body Attribute", it will show with some gibberish content and with red background, no worries... just click it to configure. Make sure you have the same setup.
However... you need to change your request to the route where you get the token from the server and another thing is the Filter (JSONPath or XPath) change it depending on your setup.
You should have the token, stored in jwt_token variable and can use the variable on a route that you like.
Example:
If you want to save a token that is returned in a response into an environment variable, you can use request chaining in your environment variable. Take a look at this url for more details on that https://support.insomnia.rest/article/43-chaining-requests...
Here is what you could do (what I did)
Create an environment variable
For the value of the variable, use the Response => Body Attribute and under Filter (JSONPath or XPath), choose the attribute of the token in your response body (if it is "token" then put $.token).
After that just put the token environment variable wherever you need it in the following requests.
I was not able to resolve this question but was able to get around it by defining the fields in the body of the request and bypassing the OAuth2 tab completely.
You can add it as a header, by referencing the outputs of the OAuth2 request:
For my project
I have created test cases in SOAPUI for Rest project.
I have to pass token in header for each test steps that I have added in the test cases.
Also the token validity only for 1 hour. So every hour I have to enter the token in the headers.
I want to know is there any way automate this token entry and generation dynamically ?
For now what I am doing is getting token every time by refreshing the URL in every 1 hour and putting it manually in header of every test case and test steps.
You could use something like the following Groovy script as the first test step of your test case. This gets your authorisation token from whatever service you use and sets it in your request header:
def authorisationToken = // Retrieve a new token from your authorisation service
// Get the headers for the request
def restRequest = testRunner.testCase.getTestStepByName('REST request')
def headers = restRequest.httpRequest.requestHeaders
// Set the token as a header. Remove it first in case it already exists
headers.remove("Authorisation") // Or whatever your header is called
headers.put("Authorisation", authorisationToken)
restRequest.httpRequest.requestHeaders = headers
If you need to, you could also create a custom property at, say, the test suite level, then set this property after you retrieve it:
testRunner.testCase.testSuite.project.setPropertyValue("Authorization", authorisationToken)
Then, you could use it anywhere you need with ${#TestSuite#authorisationToken}
I'm struggling to figure out how I can do role-based authorization depending on what HTTP method a request is using. I use HTTP basic auth and depending on the users role and the HTTP method used a request should succeed or fail.
Example:
a GET request to http://localhost/rest/ should always be allowed, even to non-authenticated users (anon access)
a PUT request to http://localhost/rest/ (same resource!) should only be allowed if user is authenticated
a DELETE request to http://localhost/rest/ (same resource!) should only be allowed if user is authenticated and has the role ADMINISTRATOR
My current (non-working) attempt of configuring shiro.ini looks like this:
/rest = authcBasic[PUT], roles[SERVICE_PROVIDER]
/rest = authcBasic[POST], roles[EXPERIMENTER]
/rest = authcBasic[DELETE], roles[ADMINISTRATOR]
/rest = authcBasic
Update
I've just found https://issues.apache.org/jira/browse/SHIRO-107 and updated my shiro.ini to be
/rest/**:put = authcBasic, roles[SERVICE_PROVIDER]
/rest/**:post = authcBasic, roles[EXPERIMENTER]
/rest/**:delete = authcBasic, roles[ADMINISTRATOR]
/rest/** = authcBasic
but it still doesn't work. It seems that only the last rule matches. Also, the commit comment also seems to indicate that this only works with permission-based authorization. Is there no equivalent implementation for role-based authz?
I think HttpMethodPermissionFilter is the one you need to configure: http://shiro.apache.org/static/1.2.2/apidocs/org/apache/shiro/web/filter/authz/HttpMethodPermissionFilter.html This should enable you to map the HTTP method to Shiro's "create,read,update,delete" permissions as outlined in the javadoc for the class.
I had a similar situation with Shiro and my REST application. While there may be a better way (I hadn't seen SHIRO-107), my solution was to create a custom filter extending the Authc filter (org.apache.shiro.web.filter.authc.FormAuthenticationFilter). You could do something similar extending the authcBasic filter or the Roles filter (although I think authcBasic would be better as it is probably more complicated).
The method you want to override is "protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)". Your argument (e.g. "ADMINISTRATOR") will come in on the mappedValue as String[] where the arguments were split by commas.
Since I needed the possibility of both a method and a role, I ended up have my arguements looks like "-". For example:
/rest/** = customFilter[DELETE-ADMINISTRATOR]
That let me split out the role required to perform a delete from the role required for a POST by doing something like:
/rest/** = customFilter[DELETE-ADMINISTRATOR,POST-EXPERIMENTER]
I think if you play with this, you'll be able to get the functionality you need.
BTW, I hadn't seen SHIRO-107, so I've not tried that technique and probably won't since I've already invented my own custom filter. However that may provide a cleaner solution than what I did.
Hope that helps!