I'm using the loopback-connector-soap and can pass my access token in like this:
var ds = loopback.createDataSource('soap',
{
...
,soapHeaders: ["..."+ token +"..."]
});
I'm putting a REST layer on top of this and I got it working. But 3rd parties will be hitting this API, so what I really need is to allow the third party to pass their token in via the header when they hit the REST route:
Authorization: Bearer _token_
The app will then place their token in the soap header. Does loopback's soap-connector allow for this scenario?
Things to try:
The loopback token module can be instructed to look for values in headers that you specify: http://apidocs.strongloop.com/loopback/#loopback-token
app.use(loopback.token({
cookies: ['foo-auth'],
headers: ['foo-auth', 'X-Foo-Auth'],
params: ['foo-auth', 'foo_auth']
}));
I use it myself for other scenarios (need it in my remote methods): https://github.com/ShoppinPal/warehouse/blob/master/server/server.js#L17, but if that doesn't "just work" meaning if that doesn't directly translate into the value also being set into the soap-connector automagically ...
Then perhaps you can use a middleware to take the value and set into the loopback context, to be later picked up by your soap connector? Here's some (crude) middleware code of mine: https://github.com/ShoppinPal/warehouse/blob/master/server/server.js#L18-L35
... but I wonder where you might write code for the soap-connector to pick that value out of the loopback context? Because right now the instantiation looks to be global and one time so I wonder when you get a chance again to edit it.
Related
This is a question about the default behaviour of #mswjs/data.toHandlers function using this example with #mswjs/data to create mocks for RTK-Query calls.
https://codesandbox.io/s/github/reduxjs/redux-toolkit/tree/master/examples/query/react/mutations?from-embed
the file src/mocks/db.ts creates a mock database using #mswjs/data and defines default http mock responses using ...db.post.toHandlers('rest') but fails to work if I remove the additional PUT and POST mocks.
My understanding is that #mswjs/data toHandlers() function provides PUT and POST mock API calls for a defined database (in this case Posts) by default according to the github documentation so I am seeking advice to understand better why toHandlers does not work for PUT and POST in this example. i.e. if i remove PUT and POST mock API calls they fail.
What do the manual PUT and POST API mocks do that the default toHandlers dont?
You are correct to state that .toHandlers() generates both POST /posts and PUT /posts/:id request handlers. The RTK-Query example adds those handlers explicitly for the following reasons:
To emulate flaky error behavior by returning an error response based on the Math.random() value in the handler.
To set the id primary key to nanoid().
Adding a post fails if you remove the explicit POST /posts handler because the model definition for post does not define the initial value for the id primary key. You cannot create an entity without providing a primary key to it, which the example does not:
// PostManager.tsx
// The "post" state only contains the name of the new post.
const [post, setPost] = useState<Pick<Post, "name">>(initialValue);
// Only the "post" state is passed to the code that dispatches the
// "POST /posts" request handled by MSW.
await addPost(post).unwrap();
If we omit the random error behavior, I think the example should've used nanoid as the initial value of the id property in the model description:
import { nanoid } from "#reduxjs/toolkit";
const db = factory({
post: {
- id: primaryKey(String),
+ id: primaryKey(nanoid),
name: String
}
});
This way you would be able to create new posts by supplying the name only. The value of the id primary key would be generated using the value getter—the nanoid function.
The post edit operation functions correctly even if you remove the explicit PUT /posts/:id request handler because, unlike the POST handler, the PUT one is only there to implement a flaky error behavior (the edited post id is provided in the path parameters: req.params.id).
Need some help with KDSoap 1.7 or gSOAP
I'm trying to use some Web Service API: http://sparkgatetest.interfax.ru/iFaxWebService/ . There is list of methods and to interact with them u must:
call Authmethod
call any method u need to
call End
Problem is, this is HTTP protocol, so if you used Authmothod succesfully, and after that trying to call methods which return some information, u got an "Authorization error" message in xml response.
So, to correct usage of this API u should call three methods (Authmethod, some method, End) in one request. How should I do it with KDSoap/gSOAP?
p.s. i found setAuthentication function in client interface, but it takes KDSoapAuthentication class as argument, maybe there is a way to customize it? And End method also a big problem aswell.
I have an authentication token I'd like to use in multiple Loopback 4 controllers. This token expires. Once expired I run some login logic to fetch a new token.
My issue is I'm not sure how or where to store this token.
So I can use this throughout my application I'm thinking to either save the token as a environment variable eg.
process.env.AUTH_TOKEN = 'TEST';
or use Loopback 4's Application-level context
https://loopback.io/doc/en/lb4/Context.html
Are these suitable solutions for storing this token? If not what would be an alternative solution?
In the case of using Context, how would I go about doing this using best practices?
Taking all the comments above into account I would recommend you to crate a separate module which will encapsulate the logic related to your authentication token and how you use it. I.e. a new module will be responsible for:
Fetching a new token when it is empty
Storing of the token
Refreshing the token when it has expired
Execution of the API calls (or whatever you do with that token, sorry it was not clear from your description) - can be moved to a separate module, but it is a different story
I imagine your module in JavaScript may look something like:
let AUTH_TOKEN = "";
function makeAPICall(some, params) {
if (! AUTH_TOKEN) {
acquireNewToken();
}
if (expired()) {
refreshToken();
}
return "some_data"; // TODO: here you do you what you want with your auth token and return some data
}
function acquireNewToken() {
authToken = "new_token"; // TODO: put the logic to acquire a new token here
}
function refreshToken() {
authToken = "new_token"; // TODO: put the logic to refresh a token here
}
function expired() {
return false; // TODO: put the logic to check if token expired here
}
module.exports = {
makeAPICall: makeAPICall
};
Then you can require the authModule in all your controllers and use it like below:
let authModule = require('./modules/authModule');
authModule.makeAPICall("some", "params");
I believe you will never need to expose the auth token to your controllers as you can implement all the logic related to auth token usage within the authModule and only pass some parameters to makeAPICall function to tell it what to do and which data to get. But in case if you really need to expose it you can change the authModule a bit (add getToken function and add it to module.exports):
function getToken() {
return authToken;
}
module.exports = {
makeAPICall: makeAPICall,
getToken: getToken
};
Now, let's get back to your questions:
Are these suitable solutions for storing this token? If not what would be an alternative solution?
As proposed above the solution is to store the token as a local variable in scope of custom module. Note, as Node.js uses caching for modules your AUTH_TOKEN variable will be the same across all the controllers (every new require will return you exactly the same object with the same token).
If you do not want to require the authModule every time you need to access your AUTH_TOKEN you can also simply declare it as a global variable: global.AUTH_TOKEN = "";. Note, that global variables have it's drawback like it may cause implicit coupling between files, etc. Here is a good article about when you should and when you should not use global variables: https://stackabuse.com/using-global-variables-in-node-js/
In the case of using Context, how would I go about doing this using
best practices?
You can use Loopback 4 Context as well and it will be almost an equivalent of the solution with the custom authModule I proposed above. The only difference with the customer module - you can put a bit more custom logic there and avoid copy-pasting some of your code in the controllers. With Loopback 4 Context you can use Server level context and store your AUTH_TOKEN there, but you will still need some place where you get a new token and refresh it when it expires. Again, you can implement this logic in the custom authModule. I.e. you can still keep that custom module and store the AUTH_TOKEN in Loopback Context at the same time. This will be absolutely OK, but it will make the code a bit more complex from my point of view.
I am using ws:outbound-gateway to invoke soap service. I have added interceptor as well.
<int-ws:outbound-gateway id="wsOutboundGateway"
request-channel="requestChannel"
uri="{soapURI}"
message-sender="httpMessageSender"
message-factory="messageFactory"
interceptor="myInterceptor"
marshaller="jaxbMarshaller" unmarshaller="jaxbMarshaller">
<int-ws:uri-variable name="soapURI" expression="headers.soapURI"/>
</int-ws:outbound-gateway>
myInterceptor is a class which implements ClientInterceptor.
Query: I have the information in message header which needs to be intercepted. Is there any way to receive the message header in the interceptor.
Note : I am setting the header value in thread local and getting back in the interceptor now.
Any better solution, please suggest.
It depends of the premise and context.
Sorry, but you have to share more info. What is the header? What do you do with that? Maybe there is no need to intercept it in the ClientInterceptor, but would be better even before <int-ws:outbound-gateway>?
UPDATE
I have the info in message header where I have to pass it in the soap header.
Actually ClientInterceptor is fully for different purpose and its intention do not modify the message.
There is WebServiceMessageCallback abstraction for message modification before sending.
But having your requirements like pass SOAP header I can suggest you to take a look into out-of-the-box component like DefaultSoapHeaderMapper. Its populateStandardHeaders deal only with SoapAction and populateUserDefinedHeader populates only as soapHeader.addAttribute(). So, consider some extension of that class to insert custom tags into soapHeader. And already without any ThreadLocal hacks.
So in my Test Plan I have a Cookie Manager setup inside my Thread Group which sets a specific Cookie value for 1 Cookie. Let's call it, MYID. I'm trying to figure out a way to verify that this specific Cookie's value was used to complete this one HTTP Request, because if I set my MYID to a specific value *(which actually tells which web server to go to), say to "Server1", but Server1 is down, unavailable, etc... HAProxy should change this and send you to Server2.
So basically I want to try and make sure that Cookie MYID was equal to "Server1" all the way through the HTTP Request.
I am trying to use a BeanShell PostProcessor to verify the Cookie's value after the request is ran, but when I tried using some code I have inside a PreProcessor that sets a cookie in a different Test Plan of mine I get an error saying:
Error Message:
Typed variable declaration : Attempt to resolve method: getCookieManager() on undefined variable or class name: sampler
And below here is the Code slightly modified from a BeanShell PreProcessor in another Test Plan I have...
CODE:
import org.apache.jmeter.protocol.http.control.Cookie;
import org.apache.jmeter.protocol.http.control.CookieManager;
CookieManager manager = sampler.getCookieManager();
for (int i = 0; i < manager.getCookieCount(); i++) {
Cookie cookie = manager.get(i);
if (cookie.getName().equals("MYID")) {
if (cookie.getValue().equals("Server1")) {
log.info("OK: The Cookie contained the Correct Server Number...");
} else {
log.info("ERROR: The Cookie did NOT contain the Correct Server Number...");
}
break;
}
}
For the error, I was thinking the "sampler" object was no longer available since the Request was already run, or something along those lines, but I'm not sure...
Or, is there another JMeter object I should be using instead of the "BeanShell PostProcessor" in order to verify the Cookie's value was correct..?
Any thoughts or suggestion would be greatly appreciated!
Thanks in Advance,
Matt
If you trying to get cookie manager from the parent sampler in the Beanshell PostProcessor - you need to use ctx.getCurrentSampler(), not "sampler" as it is not exposed in script variables.
So just change this line:
CookieManager manager = sampler.getCookieManager();
to
CookieManager manager = ctx.getCurrentSampler().getCookieManager();
And your script should start working as you expect.
ctx is a shorthand to JMeterContext instance and getCurrentSampler() method name is self-explanatory.
For more information on Beanshell scripting check out How to use BeanShell: JMeter's favorite built-in component guide.