How to update ServiceNow table using jboss fuse connector - jbossfuse

Input JSON to REST API
`{
"userName" : "UserName",
"password" : "Password",
"instance" : "Instance Name",
"table":"incident",
"sysId": "9d385017c611228701d22104cc95c371",
"model":"{'assigned_to':'681b365ec0a80164000fb0b05854a0cd','urgency':'2','comments':'Elevating urgency, this is a blocking issue'}"
}`
Processor contains following headers :
` Map<String, Object> headers = new HashMap<>();
headers.put(ServiceNowConstants.ACTION, ServiceNowConstants.ACTION_UPDATE);
headers.put(ServiceNowConstants.RESOURCE, "table");
headers.put(ServiceNowConstants.TABLE, msg.getTable());
headers.put(ServiceNowConstants.SYSPARM_ID , msg.getSysId());
headers.put(ServiceNowConstants.MODEL, msg.getModel());
exchange.getOut().setHeaders(headers);`
Spring Camel Context Bean File has endpoint:
`servicenow://${header.instance}?userName=${header.name}&password=${header.password}&apiUrl=${header.apiUrl}`
Output:
`<h2>HTTP ERROR 500</h2>
<p>Problem accessing /servicenow/update. Reason:
<pre>model must be specified</pre>`
CamelServiceNowModel is mentioned as Class in documentation, however there is no implementation of same. Please do help so to place Model String/Class in right place to update in ServiceNow.

As per the documentation of ServiceNow REST API, the POST/PATCH operations, the data is supposed to be sent in Body
This is solved with below snippet
Map<String, Object> body = new HashMap<>();
body.put("short_description", msg.getShort_description());
body.put("priority", msg.getPriority());
exchange.getOut().setBody(body);
ServiceNowConstants.MODEL accepts the String (class Path)
headers.put(ServiceNowConstants.MODEL, "java.util.HashMap");

Related

How to make a RESTful call using Basic Authentication in apache camel?

I have an apache camel application that requires sending log files to an endpoint and this requires Basic Authentication. I was able to pass the authMethod, authusername and authPassword to the url as specified in the camel documentation but the challange I'm having is that I keep getting null response from the endpoint after starting the application.
However, the same endpoint returns response code and response body using postman.
Below is my code:
from("{{routes.feeds.working.directory}}?idempotent=true")
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
multipartEntityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
String fileName = exchange.getIn().getHeader(Exchange.FILE_NAME, String.class);
File file = exchange.getIn().getBody(File.class);
multipartEntityBuilder.addPart("file",
new FileBody(file, ContentType.MULTIPART_FORM_DATA, fileName));
exchange.getOut().setBody(multipartEntityBuilder.build());
Message out = exchange.getOut();
int responseCode = out.getHeader(Exchange.HTTP_RESPONSE_CODE, Integer.class);
log.info("response code "+responseCode);
}
})
.setHeader(Exchange.HTTP_QUERY,
constant("authMethod=Basic&authUsername="+username+"&authPassword="+password+""))
.to(TARGET_WITH_AUTH +"/"+uuid+"/files")
.log(LoggingLevel.DEBUG, "response code >>>>"+Exchange.HTTP_RESPONSE_CODE)
.log(LoggingLevel.INFO, "RESPONSE BODY ${body}")
.end();
Kindly help review and advise further
For HTTP basic authentication I use this before sending a request
<setHeader headerName="Authorization">
<constant>Basic cm9vdDpyb290</constant>
</setHeader>
cm9vdDpyb290 - Encoded Base64 root:root(username and password) string
This was fixed by using httpClient to send my requests with Basic Authentication. Apparently, authMethod in apache camel doesn't send the credentials along with the Post Request and that's why I was getting the initial 401 response code.
Thank y'all for your contributions.

How to access custom header from AWS Lambda Authorizer?

I have created an Authorizer in AWS API Gateway. This Authorizer refers to a Lambda Function.
I am passing the following values in header, to the API Endpoint using Postman.
{
"type":"TOKEN",
"authorizationToken": "testing2",
"methodArn": "arn:aws:execute-api:us-west-2:444456789012:ymy8tbxw7b/*/GET/"
}
The above header values are received in the Lambda Function. I can see this through the logs in CloudWatch.
I want to pass additional value 'clientID' in the header. So I pass the following values in the header from postman.
{
"type":"TOKEN",
"authorizationToken": "testing2",
"methodArn": "arn:aws:execute-api:us-west-2:123456789012:ymy8tbxw7b/*/GET/",
"clientID" : "1000"
}
In this case, the Lambda function does not get the clientID. I checked various threads in SO, and understood that this can be achieved mapping header. So I did the following.
In the "Method Execution" section of the API method, I created a new header clientID. In the "Integration Request" section, under "HTTP Headers" section I provided the following value
Name: clientID
Mapped from: method.request.header.clientID
After doing the above, I deployed the API and tried to call the method from Postman, but the clientID is shown undefined. Following is the code that I have written in Lambda Function
exports.handler = function(event, context, callback) {
var clientid = event.clientID;
//I always get event.clientID undefined
console.log("The client ID is:" + event.clientID);
}
EDIT
Following is the error from the CloudWatch Log.
START RequestId: 274c6574-dea5-4009-b777-a929f84b9a9d Version: $LATEST
2019-09-19T09:40:25.944Z 274c6574-dea5-4009-b777-a929f84b9a9d INFO The client ID is:undefined
2019-09-19T09:40:25.968Z 274c6574-dea5-4009-b777-a929f84b9a9d ERROR Invoke Error
{
"errorType": "Error",
"errorMessage": "Unauthorized",
"stack": [
"Error: Unauthorized",
" at _homogeneousError (/var/runtime/CallbackContext.js:13:12)",
" at postError (/var/runtime/CallbackContext.js:30:51)",
" at callback (/var/runtime/CallbackContext.js:42:7)",
" at /var/runtime/CallbackContext.js:105:16",
" at Runtime.exports.handler (/var/task/index.js:40:4)",
" at Runtime.handleOnce (/var/runtime/Runtime.js:66:25)",
" at process._tickCallback (internal/process/next_tick.js:68:7)"
]
}
I have understood why I was not getting the value in the header. I have done the following
1) Instead of type TOKEN, I used type REQUEST in the header. I understood this by reading the following link. This link also contains code for Request type.
https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html
2) I removed all the mapping from Method Request and Integration Request.
3) Deployed the API.

Integration Tests fail with JWT Authorization on OpenLiberty

Integration Tests (production code works well) fail while requesting REST endpoints secured with #RolesAllowed.
Following error is thrown:
[5/20/19 8:44:21:363 CEST] 00000109 com.ibm.ws.security.jaspi.JaspiServiceImpl I CWWKS1652A: Authentication failed with status AuthStatus.SEND_FAILUR for the web request
/banking/users/bed6109f-ef8a-47ec-8fa4-e57c71415a10. The user defined Java Authentication SPI for Containers (JASPIC) service null has determined that the authentication data is not valid.
Project is based on OpenLiberty with JWT. The difference is in the UI part. My UI is based on Angular, so for authentication (JWT issuing) following REST Endpoint is used:
#RequestScoped
#Path("/tokens")
#PermitAll
public class AuthResource {
#Inject
private SecurityContext securityContext;
#Inject
private AuthService authService;
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response getJwt() {
if (securityContext.isCallerInRole("USER") || securityContext.isCallerInRole("ADMIN")) {
String name = securityContext.getCallerPrincipal().getName();
AuthPojo authPojo = authService.createJwt(name);
return Response.ok(authPojo).build();
}
return Response.status(Response.Status.UNAUTHORIZED).build();
}
}
So:
UI (Angular) calls https://localhost:5051/tokens with Header "Authorization: Basic ENCODED_USERNAME_PASSWORD"
Backend responds with newly generated JWT Token in body and Header "Set-Cookie: LtpaToken2=SOME_TOKEN; Path=/; HttpOnly"
UI uses this token for all other requests against REST Endpoints annotated with "#RolesAllowed({"ADMIN", "USER" })"
Once again, in production code, all this schema works well, but Integration Tests fail.
Here is Integration Test code:
public class MyResourceIT {
private static final String URL = "https://localhost:" +
System.getProperty("liberty.test.ssl.port") + "/users/" + USER_ID1;
private String authHeader;
#Before
public void setup() throws Exception {
authHeader = "Bearer " + new JwtVerifier().createAdminJwt(USER_NAME1);
}
#Test
public void getUserAndAccounts() {
Response response = HttpClientHelper.processRequest(URL, "GET", null, authHeader);
System.out.println("My URL: " + URL);
System.out.println("My Header: " + authHeader);
assertThat("HTTP GET failed", response.getStatus(), is(Response.Status.OK.getStatusCode()));
}
}
Looks like the problem why 401 instead 200 is returned is LtpaToken2 Cookie which is not set in Test. Instead Header "Authorization: Bearer JWT_TOKEN" is used, but this doesn't work.
I Expect that Endpoint secured with "#RolesAllowed" should respond with 200 when header "Authorization: Bearer JWT_TOKEN" is provided. Are there some tricks that should be done with a cookie?
UPDATE 2019-05-23
This is the whole project.
Example test is located here. The failing test is ignored
#Test
public void getUserAndAccounts_withJwt_authorized() throws IOException {
Response response = HttpClientHelper.processRequest(URL, "GET", null, authHeader, null);
assertThat(response.getStatus(), is(Response.Status.OK.getStatusCode()));
}
JWT token is created within following class in the #Before annotated method:
private String authHeader;
#Before
public void setup() throws Exception {
authHeader = "Bearer " + new JwtVerifier().createAdminJwt(USER_NAME1);
}
One thing to notice, that project is based on the following project.
Since the CWWKS1652A message was issued without a provider name, this indicates that appSecurity-3.0 is set and that at least a JSR-375 (a.k.a. Java EE Security API Specification) HttpAuthenticationMechanism is configured for the application, either via annotation or bean implementation. This causes an internal JASPIC provider to be created, therefore the null in the CWWKS1652A message, and this provider invokes the configured HttpAuthenticationMechanism that returns a AuthStatus.SEND_FAILURE status.
Please ensure that you intend to use an HttpAuthenticationMechanism and that valid authentication credentials are passed when challenged by this mechanism.
If it is determined that there is no HttpAuthenticationMechanism configured, then determine if there is an external JASPIC provider factory (AuthConfigFactory implementation) set via the authconfigprovider.factory property. In either case, it is the provider that responds with the AuthStatus.SEND_FAILURE seen in the message.

how to log SOAP request/response using log4j2 in separate log files dynamically

Need to write separate log files based on an apikey using log4j2 for SOAP request and response. we are client side or consuming SOAP webservice.
I am able to write separate log files based on an apikey for REST request & response but not sure how to do for SOAP request & response
code to write logs in separate log files is as follows
Need to write separate log files based on an apikey using log4j2 for SOAP request and response. we are client side or consuming SOAP webservice.
I am able to write separate log files based on an apikey for REST request & response but not sure how to do for SOAP request & response
code to write logs in separate log files is as follows :
public final class SPRestLog4j2Logger extends org.apache.logging.log4j.core.async.AsyncLogger {
private SPRestLog4j2Logger(LoggerContext context, String name, MessageFactory msgFactory) {
super(context, name, msgFactory);
this.setLevel(Level.ALL);
}
public static SPRestLog4j2Logger configureCategoryLogger(String apiKey, String loggingPath) {
LoggerContext context = new AsyncLoggerContext(apiKey);
MessageFactory msgFactory = new FormattedMessageFactory();
SPRestLog4j2Logger logger = new SPRestLog4j2Logger(context, apiKey, msgFactory);
RandomAccessFileAppender appender = RandomAccessFileAppender
.createAppender(
loggingPath + apiKey + ".log", // filename
"true", // append
"file_appender-" + apiKey, // name
"true", // immediateFlush
"", // bufferSize
"true", // ignoreExceptions
PatternLayout.createLayout(
"%-5p - [%d] - [%t] - [%l] : %m%n", null,
null, Charset.forName("UTF-8"), true, true, apiKey, apiKey), null, // filter
"false", // advertise
null, // advertiseURI
null // config
);
ConsoleAppender consoleAppender = ConsoleAppender.createAppender(
PatternLayout.createLayout(
"%-5p - [%d] - [%t] - [%l] : %m%n", null,
null, Charset.forName("UTF-8"), true, true, apiKey, apiKey), null, null,
"Console", null, null);
appender.start();
consoleAppender.stop();
logger.getContext().getConfiguration().getLoggerConfig(apiKey)
.addAppender(appender, Level.TRACE, null);
logger.getContext().getConfiguration().getLoggerConfig(apiKey)
.addAppender(consoleAppender, Level.OFF, null);
return logger;
}
}
code used to write SOAP request / response to file is as follows :
SalesCustomerSelectService customerService = new SalesCustomerSelectService(wsdlURL, SERVICE_NAME);
SalesCustomerSelect customerPort = customerService.getPort(SERVICE_NAME1, SalesCustomerSelect.class);
if (isLogging()) {
Client client = ClientProxy.getClient(customerPort);
client.getInInterceptors().add(new LoggingInInterceptor());
client.getOutInterceptors().add(new LoggingOutInterceptor());
}
But not sure how to write SOAP request/response in separate log files dynamically.
You could write your own custom Interceptor in which you log the SOAP request/response to their respective log file.
Looks like you are using Apache CXF. The documentation contains a section on writing custom Interceptors. In addition you can checkout following example.

Alfresco 4.2.c rest api: create site giving error

I am trying to create a site using alfresco 4.2.c rest api /alfresco/wcservice/api/sites (PUT)
I am using admin user so no issues with permissions.
I am able to create site successfully using the alfresco share UI
String objectToPost = "{\"shortName\":\"firm007\", \"title\":\"firm007\", \"description\":\"firm007\", \"visibility\":\"PRIVATE\", \"isPublic\":\"false\", \"sitePreset\":\"site-dashboard\"}";
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
HttpEntity<String> entity = new HttpEntity<String>(objectToPost,headers);
String url = PRE_URL + "/alfresco/wcservice/api/sites"+"?alf_ticket="+ TICKET;
String response = restTemplate.exchange(url,HttpMethod.POST, entity, String.class, new Object[] {}).toString();
System.out.println("Created SITE response is =" + response);
I am getting 500 Internal Server Error on client side code
and on alfresco server, I am getting following stack traces.
please can you help solve this issue.
I want to create an alfresco site, through a remote REST api call
2014-06-17 08:39:38,232 ERROR [freemarker.runtime] [http-apr-8080-exec-4] Template processing error: "Expression site.shortName is undefined on line 9, column 56 in org/alfresco/repository/site/site.lib.ftl."
Expression site.shortName is undefined on line 9, column 56 in org/alfresco/repository/site/site.lib.ftl.
The problematic instruction:
==> ${url.serviceContext + "/api/sites/" + site.shortName} escaped ${jsonUtils.encodeJSONString(url.serviceContext + "/api/sites/" + site.shortName)} [on line 9, column 17 in org/alfresco/repository/site/site.lib.ftl]
in user-directive siteJSONManagers [on line 2, column 1 in org/alfresco/repository/site/site.lib.ftl]
in user-directive siteLib.siteJSON [on line 2, column 1 in org/alfresco/repository/site/sites.post.json.ftl]
Java backtrace for programmers:
freemarker.core.InvalidReferenceException: Expression site.shortName is undefined on line 9, column 56 in org/alfresco/repository/site/site.lib.ftl.
Caused by: freemarker.core.InvalidReferenceException: Expression site.shortName is undefined on line 9, column 56 in org/alfresco/repository/site/site.lib.ftl.
at freemarker.core.TemplateObject.assertNonNull(TemplateObject.java:125)
at freemarker.core.Expression.getStringValue(Expression.java:118)
at freemarker.core.AddConcatExpression._getAsTemplateModel(AddConcatExpression.java:98)
at freemarker.core.Expression.getAsTemplateModel(Expression.java:89)
at freemarker.core.ListLiteral.getModelList(ListLiteral.java:119)
at freemarker.core.MethodCall._getAsTemplateModel(MethodCall.java:91)
at freemarker.core.Expression.getAsTemplateModel(Expression.java:89)
at freemarker.core.Expression.getStringValue(Expression.java:93)
solved this little puzzler.
I had not added the content-type as "application/json" hence the request was barking up the wrong tree and going to ftl instead of json
following code works fine creating a site in alfresco.
headers.set("Content-Type", "application/json");
String objectToPost = "{\"shortName\":\"firm008\", \"title\":\"firm008\", \"description\":\"firm008\", \"visibility\":\"PRIVATE\", \"isPublic\":\"false\", \"sitePreset\":\"site-dashboard\"}";
System.out.println(objectToPost);
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
**headers.set("Content-Type", "application/json");**
HttpEntity<String> entity = new HttpEntity<String>(objectToPost,headers);
String url = PRE_URL + "/alfresco/wcservice/api/sites"+"?alf_ticket="+ TICKET;
String response = restTemplate.exchange(url,HttpMethod.POST, entity, String.class, new Object[] {}).toString();
System.out.println("Created SITE response is =" + response);