I'm new to developing rest web services and now, I'm trying to add authenication via this url:
http://developers-blog.helloreverb.com/enabling-oauth-with-swagger/
Unfortunately, I'm stuck on the first step, when it says to edit the resource listing, which I believe is the api-docs, right? So, how am I supposed to edit that if its generated by the service and not stored as a file anywhere?
My Swagger version is 1.2
The link you provided refers to Swagger 1.2 but the latest version is Swagger 2.0
As a starting point, you may consider using editor.swagger.io and reviewing the petstore example, which contains authentication-related setting
Take a look at the pet store sample from the 1.3.12 tag which was the last version producing Swagger 1.2 - https://github.com/swagger-api/swagger-core/tree/v1.3.12/samples/java-jaxrs.
Specifically, you need to add the definitions to something like your Bootstrap class:
public class Bootstrap extends HttpServlet {
static {
// do any additional initialization here, such as set your base path programmatically as such:
// ConfigFactory.config().setBasePath("http://www.foo.com/");
ApiInfo info = new ApiInfo(
"Swagger Sample App", /* title */
"This is a sample server Petstore server. You can find out more about Swagger " +
"at http://swagger.io or on irc.freenode.net, #swagger. For this sample, " +
"you can use the api key \"special-key\" to test the authorization filters",
"http://helloreverb.com/terms/", /* TOS URL */
"apiteam#wordnik.com", /* Contact */
"Apache 2.0", /* license */
"http://www.apache.org/licenses/LICENSE-2.0.html" /* license URL */
);
List<AuthorizationScope> scopes = new ArrayList<AuthorizationScope>();
scopes.add(new AuthorizationScope("email", "Access to your email address"));
scopes.add(new AuthorizationScope("pets", "Access to your pets"));
List<GrantType> grantTypes = new ArrayList<GrantType>();
ImplicitGrant implicitGrant = new ImplicitGrant(
new LoginEndpoint("http://petstore.swagger.wordnik.com/oauth/dialog"),
"access_code");
grantTypes.add(implicitGrant);
AuthorizationType oauth = new OAuthBuilder().scopes(scopes).grantTypes(grantTypes).build();
ConfigFactory.config().addAuthorization(oauth);
ConfigFactory.config().setApiInfo(info);
}
}
Related
I am developing an application with JWT authentication on the google cloud platform. Server side I added authentication via Cloud API Gateway to a cloud run backend. Now I am making a client to generate the JWT token and pass it in the call. To do this I am creating an application that must be deployed on CloudRun and I am following this documentation: https://cloud.google.com/api-gateway/docs/authenticate-service-account#making_an_authenticated_request. My problem is that I don't know how to indicate what it requires as saKeyfile. I tried to put only the name of the file that under src / main / resources / filetest.json but once I try to call the method it tells me file not found. I tried to indicate also the full path. Can anyone help me?
PS I'm using Java
EDIT:
here is my code which is the same of documentation
public void makeCall() {
String fullPath="src/main/resources/TEST1-id.json";
String saEmail="testsa#projectID.iam.gserviceaccount.com";
String audience="auth";
int expiryLenght=600;
String token;
try {
token=generateJwt(fullPath,saEmail,audience,expiryLenght);
System.out.println("Token generated: "+token);
URL url = new URL("apigatewayurl");
makeJwtRequest(token, url);
System.out.println("Call performed");
} catch (IOException e) {
e.printStackTrace();
}
}
private static String generateJwt(final String saKeyfile, final String saEmail,
final String audience, final int expiryLength)
throws FileNotFoundException, IOException {
Date now = new Date();
Date expTime = new Date(System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(expiryLength));
// Build the JWT payload
JWTCreator.Builder token = JWT.create()
.withIssuedAt(now)
// Expires after 'expiraryLength' seconds
.withExpiresAt(expTime)
// Must match 'issuer' in the security configuration in your
// swagger spec (e.g. service account email)
.withIssuer(saEmail)
// Must be either your Endpoints service name, or match the value
// specified as the 'x-google-audience' in the OpenAPI document
.withAudience(audience)
// Subject and email should match the service account's email
.withSubject(saEmail)
.withClaim("email", saEmail);
// Sign the JWT with a service account
FileInputStream stream = new FileInputStream(saKeyfile);
ServiceAccountCredentials cred = ServiceAccountCredentials.fromStream(stream);
RSAPrivateKey key = (RSAPrivateKey) cred.getPrivateKey();
Algorithm algorithm = Algorithm.RSA256(null, key);
return token.sign(algorithm);
}
i've tried to use full path like in example and using only /TEST1-id.json
and here there is project structure. Is a springboot application which i will deploy in cloud run
The OP fixed the issue on this way
In the end I put the file in the root and copied it in the docker image and recover it as an environment variable in cloud run
I want to create a program that will receive notifications from my Google Classroom in question, and do something with that data. How can I register Google Classroom to react to an event?
I haven't made anything yet, and I don't know anything about Google's APIs. What should I do?
The process of registering the Google Classroom API for push notifications includes authentication, authorization, and parsing a request to Google to tell your Classroom to send these push notifications.
I highly recommend you have basic knowledge of the Google Cloud platform in the Java programming language, unlike me when I tried to do this. Trust me... it wasn't fun.
I do believe you will understand this concept enough to be able to transfer it to your language of choice, I did this in Java, using IntelliJ IDEA as my IDE.
Apart from the Google Classroom API, Google features another service to their collection called "Pub/Sub". Pub/Sub stands for Publisher/Subscriber. If you're familiar with how a queue works, think of Pub/Sub as a sort of refined queue system. You have a publisher, who posts messages on a "topic", and a subscriber to the topic who will pull messages from the topic, and choose to "acknowledge" the message or not. Acknowledging a message deletes it from the queue. For example, the publisher code sends the message "Hello, World" to a topic. That message will stay in the topic until a subscriber to that topic chooses to pull the message, read "Hello, World", and acknowledge the message, so it doesn't pop up again when pulling messages. The publisher can send as many messages as it wants. The publisher can send 10 messages, and the subscriber can choose to pull them all and iterate through them or just a few at a time.
This applies to this system because you're going to use a built-in function of the Google Classroom API that allows the API to act as a "publisher" and send update messages to a topic of your choosing. Then, you'll have a separate application checking for updates whenever you'd wish. To simplify it for now, you tell the Classroom API to "Please send update messages to this topic. I only want updates when the teacher edits the course work catalog in any way". This request will be followed by the Classroom API and the program will send messages to your topic whenever a teacher edits, or posts, or deletes, and such more.
If your classroom publisher sent 5 updates in a day, you'll have 5 pullable messages sent to your topic that any subscribing program of that topic can pull and acknowledge.
If you do not understand enough, in your opinion. Please, please do some research on Google Cloud Pub/Sub before continuing, since doing this basically revolves around this service.
Let's do this step-by-step...
Create a new project
Enable Classroom API and PubSub API
Enable Billing
Go to "IAM & admin"
Give the owner permission to "classroom-notifications#system.gserviceaccount.com"
Set up credentials for Classroom API and a "UI-based platform" using "User data"
Set up the consent screen. Just add an application name for now.
Create credentials as an "OAuth Client ID"
Choose Application Type > Other. Don't mind the client name
Download the JSON file. Rename it to "credentials_temp.json"
Create a Gradle based Java project (I'm using IntelliJ). Group id: temp. Artifact id: temp. Project name: temp
Add this to build.gradle under "dependencies"
compile 'com.google.api-client:google-api-client:1.23.0'
compile 'com.google.oauth-client:google-oauth-client-jetty:1.23.0'
compile 'com.google.apis:google-api-services-classroom:v1-rev135-1.23.0'
Set the sourceCompatibility variable in build.gradle to 11
Import those changes (There may be a little box at the bottom-right saying "import changes" as an option)
Put the credentials file in src/main/resources
In src/main/java, make a new class. Name it "TempTest.java"
Use this code I've written for you
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.util.store.FileDataStoreFactory;
import com.google.api.services.classroom.Classroom;
import com.google.api.services.classroom.model.*;
import java.io.*;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.List;
import static com.google.api.services.classroom.ClassroomScopes.all;
public class TempTest {
private static final String APPLICATION_NAME = "Google Classroom API Java Quickstart";
private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
private static final String TOKENS_DIRECTORY_PATH = "tokens";
private static final String CREDENTIALS_FILE_PATH = "/credentials.json";
private static List<String> SCOPES = new ArrayList<>();
private static Classroom service;
private static String TOPIC_NAME = "projects/temp-260404/topics/temp";
private static String COURSE_ID = "47737005203";
static {
SCOPES.addAll(all());
}
public static void main(String... args) throws IOException, GeneralSecurityException {
final var HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
service = buildClassroomService(HTTP_TRANSPORT);
// registerForPushNotifications();
List<Course> courses = getAllCourses();
if (courses == null || courses.size() == 0)
System.out.println("No courses found.");
else {
System.out.println("\nCourses:");
for (var currentCourse : courses)
System.out.println(currentCourse.getName() + "(" + currentCourse.getId() + ")");
}
}
private static void registerForPushNotifications() throws IOException {
final var pubSupTopic = new CloudPubsubTopic()
.setTopicName(TOPIC_NAME);
final var courseWorkChangesInfo = new CourseRosterChangesInfo()
.setCourseId(COURSE_ID);
final var feed = new Feed()
.setFeedType("COURSE_WORK_CHANGES")
.set("courseWorkChangesInfo", courseWorkChangesInfo);
Registration notificationsRegistration = new Registration()
.setFeed(feed)
.setCloudPubsubTopic(pubSupTopic);
pubSupTopic.setFactory(JSON_FACTORY);
courseWorkChangesInfo.setFactory(JSON_FACTORY);
feed.setFactory(JSON_FACTORY);
notificationsRegistration.setFactory(JSON_FACTORY);
service.registrations().create(notificationsRegistration).execute();
System.out.println("Successfully registered");
}
private static Classroom buildClassroomService(final NetHttpTransport HTTP_TRANSPORT) throws IOException {
final var serviceCredentials = getCredentials(HTTP_TRANSPORT);
return new Classroom.Builder(HTTP_TRANSPORT, JSON_FACTORY, serviceCredentials)
.setApplicationName(APPLICATION_NAME)
.build();
}
private static Credential getCredentials(final NetHttpTransport HTTP_TRANSPORT) throws IOException {
final var clientSecrets = loadJSONClientSecrets();
final var dataStoreFactory = new FileDataStoreFactory(new File(TOKENS_DIRECTORY_PATH));
final var authenticationFlow = new GoogleAuthorizationCodeFlow.Builder(
HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
.setDataStoreFactory(dataStoreFactory)
.setAccessType("offline")
.build();
return redirectToAuthentication(authenticationFlow);
}
private static GoogleClientSecrets loadJSONClientSecrets() throws IOException {
final var credentialFileStream = getCredentialsJSONFile();
if (credentialFileStream == null)
throw new FileNotFoundException("Resource not found: " + CREDENTIALS_FILE_PATH);
return GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(credentialFileStream));
}
private static InputStream getCredentialsJSONFile() {
return TempTest.class.getResourceAsStream(CREDENTIALS_FILE_PATH);
}
private static Credential redirectToAuthentication(GoogleAuthorizationCodeFlow flow) throws IOException {
final var receiver = new LocalServerReceiver.Builder().setPort(8888).build();
return new AuthorizationCodeInstalledApp(flow, receiver).authorize("user");
}
private static List<Course> getAllCourses() throws IOException {
ListCoursesResponse response = service.courses().list()
.execute();
return response.getCourses();
}
}
Go to Google Classroom and create your own Classroom for testing purposes.
Go to Pub/Sub and create a new topic. Make sure it's set to "Google managed key". Get its name under "Topic name" when it's made. There is a little button for copying the full path.
Set the TOPIC_NAME field of the class to a String containing the topic name you just copied
Run the code and authorize with all scopes. You will be redirected. Make sure you choose the same account you use Cloud Platform on.
Running it will give you a list of your courses and their ID numbers in parentheses. Copy the ID number of the test course you made. It should be outputted to the console after running your code.
Set the COURSE_ID field of the class to a String containing the ID you just copied
Uncomment line 40 and run the code again
You're done with my example
What you just did was authenticate yourself so Google Knows what permissions you're giving it, and it can verify your identity. Then, you sent a JSON request to Google with information about what topic you want updates to be published to, the type of updates to get, and the specific classroom to get these updates from.
I highly, HIGHLY recommend you learn how the structure of the JSON response works here.
Perhaps start here.
This page on the Google documentation has decent information. It also shows the JSON formatting of the message you'll pull from another program using the Google Pub/Sub API. I have not included that here.
Thank you, and good luck. Sorry, I may edit this question a few times. I'm really tired right now.
I am trying my first web app service using Azure services. I've created it in VS, and it works locally. All it does it return a string that says "hello user" is JSON.
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Service1
{
// To use HTTP GET, add [WebGet] attribute. (Default ResponseFormat is WebMessageFormat.Json)
// To create an operation that returns XML,
// add [WebGet(ResponseFormat=WebMessageFormat.Xml)],
// and include the following line in the operation body:
// WebOperationContext.Current.OutgoingResponse.ContentType = "text/xml";
[OperationContract]
[WebGet(UriTemplate = "/DoWork")]
public string DoWork()
{
// Add your operation implementation here
return "hello user";
}
// Add more operations here and mark them with [OperationContract]
}
}
Problem is when I publish it, says successful. I can see it running on portal.
When I goto published site I get the standard THIS WEB APP HAS BEEN SUCCESSFULLY CREATED, but... when I add the /DoWork to the URL I get HTTP error 404.
I know I must be missing something simple...
any ideas?
you're missing the name of the service. In your case would be something like:
http://engineappservicev001.azurewebsites.net/something.svc/dowork
More info in here:
http://www.codeproject.com/Articles/571813/A-Beginners-Tutorial-on-Creating-WCF-REST-Services
I'm currently trying to call Amazon Product Retail Web Service in Salesforce.
As I mentioned in
Getting WSDL parse error while generating Apex code from WSDL in Salesforce
I was initially unable to generate apex stub class, but I followed the method suggested by #Ballinger and created apex class. I wrote an apex class to use that stub and to set request parameters. The class i wrote is as follows
public class AmazonProductStubNew
{
public static void getResults()
{
System.Debug(' getResults start ');
AmazonWS.AWSECommerceServicePortUS stub = new AmazonWS.AWSECommerceServicePortUS();
stub.inputHttpHeaders_x = new Map<String,String>();
stub.inputHttpHeaders_x.put('AWSAccessKeyId','MyAmazonAWSAccessKeyId');
stub.inputHttpHeaders_x.put('Timestamp','2012-11-28T12:11:30Z');
stub.inputHttpHeaders_x.put('Signature','Encrypted Secret Code');
String MarketplaceDomain = '';
String AWSAccessKeyId = 'MyAmazonAWSAccessKeyId';
String AssociateTag = '';
String XMLEscaping = '';
String Validate = '';
AmazonWS.ItemSearchRequest Shared = new AmazonWS.ItemSearchRequest();
Shared.SearchIndex = 'DVD';
AmazonWS.ItemSearchRequest[] Request = new AmazonWS.ItemSearchRequest[1];
Request[0] = new AmazonWS.ItemSearchRequest();
Request[0].Title = 'Inception';
AmazonWS.ItemSearchResponse_element response = stub.ItemSearch(MarketplaceDomain,AWSAccessKeyId,AssociateTag,XMLEscaping,Validate,Shared,Request);
AmazonWS.Items_element[] localItems = response.Items;
System.Debug(localItems[0].TotalResults);
}
}
Even though I've added HTTP headers to stub, I'm not getting it in XML Request message
XML Request is as follows
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Header />
<env:Body>
<ItemSearch xmlns="http://webservices.amazon.com/AWSECommerceService/2011-08-01">
<MarketplaceDomain>
</MarketplaceDomain>
<AWSAccessKeyId>MyAWSAccessKeyId</AWSAccessKeyId>
<AssociateTag></AssociateTag>
<XMLEscaping></XMLEscaping>
<Validate></Validate>
<Shared><SearchIndex>DVD</SearchIndex></Shared>
<Request><Title>Inception</Title>
</Request></ItemSearch>
</env:Body></env:Envelope>
Since headers are not there in SOAP Request, There is a SOAP fault asking for Signature from Amazon Server.
As you can see, I'm new to Salesforce Apex. I followed the steps in
http://www.salesforce.com/us/developer/docs/apexcode/index_Left.htm#StartTopic=Content/apex_web_services_wsdl2apex.htm#http_header_support
to set the headers.
Any idea on why the header isn't getting added?
P.S I added headers manually and tried in SOAP UI, I'm getting proper response.
Thanks :)
I think you're using wrong functions :) (question is indeed confusing).
SOAP (or generally HTTP) communication consists of sending headers and actual message (payload if you like). Headers are short text thingies, message is often a giant XML.
Your code is setting HTTP headers (which are used in web communication to authenticate, provide info about your browser, preferred languages, set cookies, return status codes like 404 page not found...) Please don't be offended with the "for dummies" but I realize the wikipedia article is a bit too much, this might be simpler: http://net.tutsplus.com/tutorials/other/http-headers-for-dummies/
And what I suspect Amazon's webservice wants is just some fields inside the <env:Header>...</env:Header> tag? Just check the generated apex code for existence of subclass called "Header" (you can also search for the variable names like "Signature". This is going to be a total wild guess but I think you'll have to write something like that:
AmazonWS.AWSECommerceServicePortUS stub = new AmazonWS.AWSECommerceServicePortUS();
AmazonWS.Header h = new AmazonWS.Header();
h.AWSAccessKeyId = 'MyAmazonAWSAccessKeyId';
h.Timestamp = '2012-11-28T12:11:30Z';
h.Signature = 'Encrypted Secret Code';
stub.Header = h; // plug it into the request
// create and plug other required tags
AmazonWS.ItemSearchRequest Shared = new AmazonWS.ItemSearchRequest();
Shared.SearchIndex = 'DVD';
AmazonWS.ItemSearchRequest[] Request = new AmazonWS.ItemSearchRequest[1];
Request[0] = new AmazonWS.ItemSearchRequest();
Request[0].Title = 'Inception';
// ...
Now, to make it more confusing you might still have to use a HTTP header, there's a special one called SOAPAction. But generally speaking I believe you're after placing your data in the XML, not in http headers.
Funny enough, I've downloaded the Java example from http://aws.amazon.com/code/Product-Advertising-API/2478 and if I read it correctly they're passing the signature in the URL (endpoint), not in the XML. Probably because it's a REST GET method (if you can access that API it could save you a lot of hair pulled, SOAP is clunky).
I'm trying to do integration with Salesforce using their REST API and CF8.
I got the OAuth bit working, getting data etc but now I'm trying to update some records in Contact table.
First I tought about doing it the "proper" way as their docs say -
Update a record using HTTP PATCH.
But CFHTTP doesn't support PATCH method.
So then I tried running a SOQL query:
UPDATE Contact SET MailingStreet = 'Blah Blah' WHERE Id = '003A000000Zp4ObIAJ'
but here I'm getting
{"message":"unexpected token: UPDATE","errorCode":"MALFORMED_QUERY"}
Does anyone have an idea how to do it?
You can create your own PATCH method if your client supports it, but there is an easier way. From the Force.com REST API Developer's Guide:
If you use an HTTP library that doesn't allow overriding or setting an
arbitrary HTTP method name, you can send a POST request and provide an
override to the HTTP method via the query string parameter
_HttpMethod. In the PATCH example, you can replace the PostMethod line
with one that doesn't use override:
PostMethod m = new PostMethod(url + "?_HttpMethod=PATCH");
In CF9 CFScript, using the method that Paddyslacker already suggested for adding _HttpMethod=PATCH to the URL:
private boolean function patchObject(required string sfid, required string type, required struct obj) {
local.url = variables.salesforceInstance & '/services/data/v' & variables.apiVersion &'/sobjects/' & arguments.type & '/' & arguments.sfid &'?_HttpMethod=PATCH';
local.http = new Http(url=local.url,method='post');
//... convert obj to a json string, add to local.http ...
local.httpSendResult = local.http.send().getPrefix();
}
We have a CF9 CFC that we wrote that wraps most of the REST API that we will be open sourcing soon. I'll come back and link to it when we do.