diff --git a/.gitignore b/.gitignore index 7aba5f8dd..824edbe8d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .settings .classpath .project +.idea diff --git a/_blog-src/_layouts/post.html b/_blog-src/_layouts/post.html index b65fcd3f4..ad47a16f0 100644 --- a/_blog-src/_layouts/post.html +++ b/_blog-src/_layouts/post.html @@ -11,7 +11,25 @@

{{ {{ page.categories | array_to_sentence_string }} -
+ + {% if page.newUrl %} + +

+ Note: A newer revision of this blogpost for apiman 1.2.x can be found here. This version was written for apiman 1.1.x. +

+ {% endif %} + + {% if page.oldUrl %} + +

+ Note: This is a redux of our blogpost for apiman 1.2.x. If you're still using apiman 1.1.x, you can refer to the older revision. +

+ {% endif %} + +
{{ content }}
diff --git a/_blog-src/_posts/2015-01-09-impatient-new-user-redux.markdown b/_blog-src/_posts/2015-01-09-impatient-new-user-redux.markdown new file mode 100644 index 000000000..6e6e9f17d --- /dev/null +++ b/_blog-src/_posts/2015-01-09-impatient-new-user-redux.markdown @@ -0,0 +1,470 @@ +--- +layout: post +title: "An Impatient New User's Introduction to API Management with JBoss apiman 1.0" +date: 2015-01-09 09:15:00 +author: len_dimaggio +categories: introduction overview +oldUrl: 2015-01-09-impatient-new-user +--- + +Software application development models are evolutionary things. New technologies are always being created +and require new approaches. It's frequently the case today, that a service oriented architecture (SOA) model +is used and that the end product is a software service that can be used by applications. The explosion in +growth of mobile devices has only accelerated this trend. Every new mobile phone sold is another platform +onto which applications are deployed. These applications are often built from services provided from multiple +sources. The applications often consume these services through their APIs. + +OK, that's all interesting, but why does this matter? + + + +Here's why: + +If you are providing an API, you'd probably like to receive payment when it's used by an client app. For +example, let's say that you've spent months creating a new API that provides incredibly accurate and +timely driving directions. You can imagine every mobile phone GPS app making use of your API someday. +That is, however, assuming that you can find a way to enforce a contract on consumers of the API and provide +them with a service level agreement (SLA). Also, you have to find a way to actually track consumers' use of +the API so that you can actually enforce that SLA. Finally, you have to have the means to update an API +and publish new versions of APIs. + +Likewise, if you are consuming an API, for example, if you want to build the killer app that will use that +cool new mapping API, you have to have the means to find the API, identify the API's endpoint, and +register your usage of the API with its provider. + +The approach that is followed to fulfill both API providers' and consumers' needs is...API Management. + +## JBoss apiman 1.0 + +apiman is JBoss' open source API Management system. apiman fulfills API providers' and consumers' +needs by implementing: + +* *API Manager* - The API Manager provides an easy way for API providers to use a web UI to define API contracts for their APIs, apply these contracts across multiple APIs, and control role-based user access and API versioning. These contracts can govern access to APIs and limits on the rate at which consumers can access APIs. The same UI enables API consumers to easily locate and access APIs. + +* *API Gateway* - The gateway applies the API contract policies of API Management by enforcing at runtime the rules defined in the contracts and tracking the API consumers' use of the APIs for every request made to the APIs. The way that the API Gateway works is that the consumer of the API accesses the API through a URL that designates the API Gateway as a proxy for the API. If the policies defined to govern access to the API (see a later section in this post for a discussion of apiman polices), the API Gateway then proxies requests to the API's backend API implementation. + +The best way to understand API Management with apiman is to see it in action. In this post, we'll install +apiman 1.0, configure an API with contracts through the API Manager, and watch the API Gateway control access +to the API and track its use. + +## Prerequisites + +We don't need very much to run apiman out of the box. Before we install apiman, you'll have to have Java (version 1.7 or newer) installed on your system. You'll also need to git and maven installed to be able to build the example API that we'll use. + +A note on software versions: In this post we'll use the latest available version of apiman as of December 2014. As if this writing, version 1.0 of apiman was just released (December 2014). Depending on the versions of software that you use, some screen displays may look a bit different. + +## Getting apiman + +Like all JBoss software, installation of apiman is simple. First, you will need a client app server on which to install and run apiman. We'll use the open source JBoss WildFly server release 8.2 [http://www.wildfly.org/](http://www.wildfly.org/). To make things easier, apiman includes a pointer to JBoss WildFly on its download page here: [http://www.apiman.io/latest/download.html](http://www.apiman.io/latest/download.html) + +To install WildFly, simply download [http://download.jboss.org/wildfly/8.2.0.Final/wildfly-8.2.0.Final.zip](http://download.jboss.org/wildfly/8.2.0.Final/wildfly-8.2.0.Final.zip) and unzip the file into the directory in which you want to run the sever. + +Then, download the apiman 1.0 WildFly overlay zip file inside the directory that was created when you un-zipped the WildFly download. The apiman 1.0 WildFly overlay zip file is available here: [http://downloads.jboss.org/apiman/1.0.0.Final/apiman-distro-wildfly8-1.0.0.Final-overlay.zip](http://downloads.jboss.org/apiman/1.0.0.Final/apiman-distro-wildfly8-1.0.0.Final-overlay.zip) + +The commands that you will execute will look something like this: + +{% highlight bash %} +mkdir apiman +cd apiman +unzip wildfly-8.2.0.Final.zip +unzip -o apiman-distro-wildfly8-1.0.0.Final-overlay.zip -d wildfly-8.2.0.Final +{% endhighlight %} + +Then, to start the server, execute these commands: + +{% highlight bash %} +cd wildfly-8.2.0.Final +./bin/standalone.sh -c standalone-apiman.xml +{% endhighlight %} + +The server will write logging messages to the screen. When you see some messages that look like this, you'll know that the server is up and running with apiman installed: + +{% highlight text %} +13:57:03,229 INFO [org.jboss.as.server] (ServerService Thread Pool -- 29) JBAS018559: Deployed "apiman-ds.xml" (runtime-name : "apiman-ds.xml") +13:57:03,261 INFO [org.jboss.as] (Controller Boot Thread) JBAS015961: Http management interface listening on http://127.0.0.1:9990/management +13:57:03,262 INFO [org.jboss.as] (Controller Boot Thread) JBAS015951: Admin console listening on http://127.0.0.1:9990 +13:57:03,262 INFO [org.jboss.as] (Controller Boot Thread) JBAS015874: WildFly 8.2.0.Final "Tweek" started in 5518ms - Started 754 of 858 services (171 services are lazy, passive or on-demand) +{% endhighlight %} + +If this were a production server, the first thing that we'd do is to change the OOTB default admin username and/or password. apiman is configured by default to use JBoss KeyCloak [http://keycloak.jboss.org/](http://keycloak.jboss.org/) for password security. Also, the default database used by apiman to store contract and API information is the H2 database. For a production server, you'd want to reconfigure this to use a production database. Note: apiman includes DDLs for both MySQL and PostgreSQL. + +For the purposes of our demo, we'll keep things simple and use the default configuration. + +To access apiman's API Manager UI, go to: [http://localhost:8080/apiman-manager](http://localhost:8080/apiman-manager), and log in. The admin user account that we'll use has a username of "admin" and a password of "admin123!" + +You should see a screen that looks like this: + +![Dashboard](/blog/images/2015-01-09/apiman_1.png) + +Before we start using apiman, let's take a look at how apiman defines how APIs and the meta data on which they depend are organized. + +## Policies, Plans, and Organizations + +apiman uses a hierarchical data model that consists of these elements: Polices, Plans, and Organizations: + +![Diagram_1](/blog/images/2015-01-09/apiman_2.jpg) + +## Policies + +Policies are at the lowest level of the data model, and they are the basis on which the higher level elements of the data model are built. A policy defines an action that is performed by the API Gateway at runtime. Everything defined in the API Manager UI is there to enable apiman to apply policies to requests made to APIs. + +When a request to an API is made, apiman creates a chain of policies to be applied to that request. apiman policy chains define a specific sequence order in which the policies defined in the API Manager UI are applied to API requests. + +The sequence in which incoming API requests have policies applied is: + +* First, at the client app level. In apiman, a client app is contracted to use one or more APIs. +* Second, at the plan level. In apiman, policies are organized into groups called plans. (We'll discuss plans in the next section of this post.) +* Third, at the individual API level. + +What happens is that when an API request is received by the API Gateway at runtime, the policy chain is applied in the order of client app, plan, and API. If no failures, such as a rate counter being exceeded, occur, the API Gateway sends the request to the API. As we mentioned earlier in this post, the API Gateway acts as a proxy for the API: + +![Diagram_2](/blog/images/2015-01-09/apiman_3-redux.jpg) + +Next, when the API Gateway receives a response from the API's backend implementation, the policy chain is applied again, but this time in the reverse order. The API policies are applied first, then the plan policies, and finally the client app policies. If no failures occur, then the API response is sent back to the consumer of the API. + +By applying the policy chain twice, both for the originating incoming request and the resulting response, apiman allows policy implementations two opportunities to provide management functionality during the lifecycle. The following diagram illustrates this two-way approach to applying policies: + +![Diagram_3](/blog/images/2015-01-09/apiman_4-redux.jpg) + +## Plans + +In apiman, a "plan" is a set policies that together define the level of service that apiman provides for API. Plans enable apiman users to define multiple different levels of service for their APIs, based on policies. It's common to define different plans for the same API, where the differences depend on configuration options. For example, a group or company may offer both a "gold" and "silver" plan for the same API. The gold plan may be more expensive than the silver plan, but it may offer a higher level of API requests in a given (and configurable) time period. + +## Organizations + +The "organization" is at top level of the apiman data model. + +An organization contains and manages all elements used by a company, university, group inside a company, etc. for API management with apiman. All plans, APIs, client apps, and users for a group are defined in an apiman organization. In this way, an organization acts as a container of other elements. Users must be associated with an organization before they can use apiman to create or consume APIs. apiman implements role-based access controls for users. The role assigned to a user defines the actions that a user can perform and the elements that a user can manage. + +Before we can define an API, the policies that govern how it is accessed, the users who will be able to access, and the organizations that will create and consume it, we need an API and a client app to access that API. Luckily, creating the API and deploying it to our WildFly server, and accessing it through a client app are easy. + +## Getting and Building and Deploying the Example API + +The source code for the example API is contained in a git repo (http://git-scm.com) hosted at github (https://github.com/apiman). To download a copy of the example API, navigate to the directory in which you want to build the API and execute this git command: + + git clone git@github.com:apiman/apiman-quickstarts.git + +As the source code is downloading, you'll see output that looks like this: + + git clone git@github.com:apiman/apiman-quickstarts.git + Initialized empty Git repository in /tmp/tmp/apiman-quickstarts/.git/ + remote: Counting objects: 104, done. + remote: Total 104 (delta 0), reused 0 (delta 0) + Receiving objects: 100% (104/104), 18.16 KiB, done. + Resolving deltas: 100% (40/40), done. + +And, after the download is complete, you'll see a populated directory tree that looks like this: + + +{% highlight text %} +└── apiman-quickstarts + ├── echo-api + │ ├── pom.xml + │ ├── README.md + │ └── src + │ └── main + │ ├── java + │ │ └── io + │ │ └── apiman + │ │ └── quickstarts + │ │ └── echo + │ │ ├── EchoResponse.java + │ │ └── EchoServlet.java + │ └── webapp + │ └── WEB-INF + │ ├── jboss-web.xml + │ └── web.xml + ├── LICENSE + ├── pom.xml + ├── README.md + ├── release.sh + └── src + └── main + └── assembly + └── dist.xml +{% endhighlight %} + +As we mentioned earlier in the post, the example API is very simple. The only action that the API performs is to echo back in responses the meta data in the REST (http://en.wikipedia.org/wiki/Representational_state_transfer) requests that it receives. + +Maven is used to build the API. To build the API into a deployable .war file, navigate to the directory into which you downloaded the API example: + + cd apiman-quickstarts/echo-api + +And then execute this maven command: + + mvn package + +As the API is being built into a .war file, you'll see output that looks like this: + +{% highlight text %} +[INFO] Scanning for projects... +[INFO] +[INFO] Using the builder org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder with a thread count of 1 +[INFO] +[INFO] ------------------------------------------------------------------------ +[INFO] Building apiman-quickstarts-echo-api 1.0.1-SNAPSHOT +[INFO] ------------------------------------------------------------------------ +[INFO] +[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ apiman-quickstarts-echo-api --- +[INFO] Using 'UTF-8' encoding to copy filtered resources. +[INFO] skip non existing resourceDirectory /jboss/local/redhat_git/apiman-quickstarts/echo-api/src/main/resources +[INFO] +[INFO] --- maven-compiler-plugin:2.5.1:compile (default-compile) @ apiman-quickstarts-echo-api --- +[INFO] Compiling 2 source files to /jboss/local/redhat_git/apiman-quickstarts/echo-api/target/classes +[INFO] +[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ apiman-quickstarts-echo-api --- +[INFO] Using 'UTF-8' encoding to copy filtered resources. +[INFO] skip non existing resourceDirectory /jboss/local/redhat_git/apiman-quickstarts/echo-api/src/test/resources +[INFO] +[INFO] --- maven-compiler-plugin:2.5.1:testCompile (default-testCompile) @ apiman-quickstarts-echo-api --- +[INFO] No sources to compile +[INFO] +[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ apiman-quickstarts-echo-api --- +[INFO] No tests to run. +[INFO] +[INFO] --- maven-war-plugin:2.2:war (default-war) @ apiman-quickstarts-echo-api --- +[INFO] Packaging webapp +[INFO] Assembling webapp in [/jboss/local/redhat_git/apiman-quickstarts/echo-api/target/apiman-quickstarts-echo-api-1.0.1-SNAPSHOT] +[INFO] Processing war project +[INFO] Copying webapp resources [/jboss/local/redhat_git/apiman-quickstarts/echo-api/src/main/webapp] +[INFO] Webapp assembled in [23 msecs] +[INFO] Building war: /jboss/local/redhat_git/apiman-quickstarts/echo-api/target/apiman-quickstarts-echo-api-1.0.1-SNAPSHOT.war +[INFO] WEB-INF/web.xml already added, skipping +[INFO] ------------------------------------------------------------------------ +[INFO] BUILD SUCCESS +[INFO] ------------------------------------------------------------------------ +[INFO] Total time: 1.184 s +[INFO] Finished at: 2014-12-26T16:11:19-05:00 +[INFO] Final Memory: 14M/295M +[INFO] ------------------------------------------------------------------------ +{% endhighlight %} + +If you look closely, near the end of the output, you'll see the location of the .war file: + + /jboss/local/redhat_git/apiman-quickstarts/echo-api/target/apiman-quickstarts-echo-api-1.0.1-SNAPSHOT.war + +To deploy the API, we can copy the .war file to our WildFly server's "deployments" directory. After you copy the API's .war file to the deployments directory, you'll see output like this generated by the WildFly server: + +{% highlight text %} +16:54:44,313 INFO [org.jboss.as.server.deployment] (MSC service thread 1-7) JBAS015876: Starting deployment of "apiman-quickstarts-echo-api-1.0.1-SNAPSHOT.war" (runtime-name: "apiman-quickstarts-echo-api-1.0.1-SNAPSHOT.war") +16:54:44,397 INFO [org.wildfly.extension.undertow] (MSC service thread 1-16) JBAS017534: Registered web context: /apiman-echo +16:54:44,455 INFO [org.jboss.as.server] (DeploymentScanner-threads - 1) JBAS018559: Deployed "apiman-quickstarts-echo-api-1.0.1-SNAPSHOT.war" (runtime-name : "apiman-quickstarts-echo-api-1.0.1-SNAPSHOT.war") +{% endhighlight %} + +Make special note of this line of output: + +{% highlight text %} +16:54:44,397 INFO [org.wildfly.extension.undertow] (MSC service thread 1-16) JBAS017534: Registered web context: /apiman-echo +{% endhighlight %} + +This output indicates that the URL of the deployed example API is: + +{% highlight text %} +[a href="http://localhost:8080/apiman-echo" style="text-decoration: none;"]http://localhost:8080/apiman-echo +{% endhighlight %} + +Remember, however, that this is the URL of the deployed example API if we access it directly. We'll refer to this as the "unmanaged API" as we are able to connect to the API directly, without going through the API Gateway. The URL to access the API through the API Gateway ("the managed API") at runtime will be different. + +Now that our example API is installed, it's time to install and configure our client app to access the server. + +## Accessing the Example API Through a Client App + +There are a lot of options available when it comes to what we can use for a client app to access our API. We'll keep the client app simple so that we can keep our focus on apiman and simply install a REST client into the FireFox browser. The REST Client FireFox add-on (http://restclient.net/) is available here: https://addons.mozilla.org/en-US/firefox/addon/restclient/versions/2.0.3 + +After you install the client into FireFox, you can access the deployed API using the URL that we just defined. If you execute a GET command, you'll see output that looks like this: + +![Screenshot 4](/blog/images/2015-01-09/Screenshot-4.png) + +Now that our example API is built, deployed and running, it's time to create the organizations for the API provider and the API consumer. The differences between the requirements of the two organizations will be evident in their apiman configuration properties. + +## Creating Users for the API Provider and Consumer + +Before we create the organizations, we have to create a user for each organization. We'll start by creating the API provider user. To do this, logout from the admin account in the API Manager UI. The login dialog will then be displayed. + +![Screenshot 5](/blog/images/2015-01-09/Screenshot-5.png) + +Select the "New user" Option and register the API provider user: + +![Screenshot 6](/blog/images/2015-01-09/Screenshot-6.png) + +Then, logout and repeat the process to register a new client app developer user too: + +![Screenshot 7](/blog/images/2015-01-09/Screenshot-7.png) + +Now that the new users are registered we can create the organizations. + +## Creating the API Producer Organization + +To create the API producer organization, log back into the API Manager UI as the servprov user and select "Create a new Organization": + +![dash-2](/blog/images/2015-01-09/apiman_2.png) + +Select a name and description for the organization, and press "Create Organization": + +![Screenshot 15](/blog/images/2015-01-09/Screenshot-15.png) + +And, here's our organization: + +![Screenshot 16](/blog/images/2015-01-09/Screenshot-16.png) + +Note that in a production environment, users would request membership in an organization. The approval process for accepting new members into an organization would follow the organization's workflow, but this would be handled outside of the API Manager. For the purposes of our demonstration, we'll keep things simple. + +## Configuring the API, its Policies, and Plans + +To configure the API, we'll first create a plan to contain the policies that we want applied by the API Gateway at runtime when requests to the API are made. To create a new plan, select the "Plans" tab. We'll create a "gold" plan: + +![Screenshot 17](/blog/images/2015-01-09/Screenshot-17.png) + +Once the plan is created, we will add policies to it: + +![Screenshot 18](/blog/images/2015-01-09/Screenshot-18.png) + +apiman provides several OOTB policies. Since we want to be able to demonstrate a policy being applied, we'll select a Rate Limiting Policy, and set its limit to a very low level. If our API receives more than 10 requests in a day, the policy should block all subsequent requests. So much for a "gold" level of service! + +![Screenshot 19](/blog/images/2015-01-09/Screenshot-19.png) + +After we create the policy and add it to the plan, we have to lock the plan: + +![Screenshot 21](/blog/images/2015-01-09/Screenshot-21.png) + +And, here is the finished, and locked plan: + +![Screenshot 22](/blog/images/2015-01-09/Screenshot-22.png) + +At this point, additional plans can be defined for the API. We'll also create a "silver" plan, that will offer a lower level of service (i.e., a request rate limit lower than 10 per day) than the gold plan. Since the process to create this silver plan is identical to that of the gold plan, we'll skip the screenshots. + +Now that the two plans are complete and locked, it's time to define the API. + +![Screenshot 23](/blog/images/2015-01-09/Screenshot-23.png) + +We'll give the API an appropriate name, so that providers and consumers alike will be able to run a query in the API Manager to find it. + +![Screenshot 24](/blog/images/2015-01-09/Screenshot-24.png) + +After the API is defined, we have to define its implementation. In the context of the API Manager, the API Endpoint is the API's direct URL. Remember that the API Gateway will act as a proxy for the API, so it must know the API's actual URL. In the case of our example API, the URL is: [http://localhost:8080/apiman-echo](http://localhost:8080/apiman-echo) + +![Screenshot 25](/blog/images/2015-01-09/Screenshot-25.png) + +The plans tab shows which plans are available to be applied to the API: + +![Screenshot 26](/blog/images/2015-01-09/Screenshot-26.png) + +Let's make our API more secure by adding an authentication policy that will require users to login before they can access the API. Select the Policies tab, and then define a simple authentication policy. Remember the user name and password that you define here as we'll need them later on when send requests to the API. + +![Screenshot 27](/blog/images/2015-01-09/Screenshot-27.png) + +After the authentication policy is added, we can publish the API to the API Gateway: + +![Screenshot 28](/blog/images/2015-01-09/Screenshot-28.png) + +And, here it is, the published API: + +![Screenshot 29](/blog/images/2015-01-09/Screenshot-29.png) + +OK, that finishes the definition of the API provider organization and the publication of the API. + +Next, we'll switch over to the API consumer side and create the API consumer organization and register a client app to connect to the managed API through the proxy of the API Gateway. + +## The API Consumer Organization + +We'll repeat the process that we used to create the client app development organization. Log in to the API Manager UI as the "appdev" user and create the organization: + +![Screenshot 30](/blog/images/2015-01-09/Screenshot-30.png) + +Unlike the process we used when we created the elements used by the API provider, the first step that we'll take is to create a new client app and then search for the API to be used by the client app: + +![Screenshot 31](/blog/images/2015-01-09/Screenshot-31.png) + +Searching for the API is easy, as we were careful to set the API name to something memorable: + +![Screenshot 32](/blog/images/2015-01-09/Screenshot-32.png) + +Select the API name, and then specify the plan to be used. We'll splurge and use the gold plan: + +![Screenshot 33](/blog/images/2015-01-09/Screenshot-33.png) + +Next, select "create contract" for the plan: + +![Screenshot 34](/blog/images/2015-01-09/Screenshot-34.png) + +Then, agree to the contract terms (which seem to be written in a strange form of Latin in the apiman 1.0 release): + +![Screenshot 35](/blog/images/2015-01-09/Screenshot-35.png) + +The last step is to register the client app with the API Gateway so that the gateway can act as a proxy for the API: + +![Screenshot 36](/blog/images/2015-01-09/Screenshot-36.png) + +Congratulations! All the steps necessary to provide and consume the API are complete! + +There's just one more step that we have to take in order for client apps to be able access the API through the API Gateway. + +Remember the URL that we used to access the unmanaged API directly? Well, forget it. In order to access the managed API through the API Gateway acting as a proxy for other API we have to obtain the managed API's URL. In the API Manager UI, head on over to the "APIs" tab for the client app, click on the the '>' character to the left of the API name. This will expose the API Key and the API's HTTP endpoint in the API Gateway: + +![Screenshot 37](/blog/images/2015-01-09/Screenshot-37.png) + +In order to be able access the API through the API Gateway, we have to provide the API Key with each request. The API Key can be provided either through an HTTP Header (X-API-Key) or a URL query parameter. Luckily, the API Manager UI does the latter for us. Select the icon to the right of the HTTP Endpoint and this dialog is displayed: + +![Screenshot 38](/blog/images/2015-01-09/Screenshot-38.png) + +Copy the URL into the clipboard. We'll need to enter this into the client app in a bit. The combined API Key and HTTP endpoint should look something like this: + +[http://localhost:8080/apiman-gateway/ACMEServices/echo/1.0?apikey=c374c202-d4b3-4442-b9e4-c6654f406e3d](http://localhost:8080/apiman-gateway/ACMEServices/echo/1.0?apikey=c374c202-d4b3-4442-b9e4-c6654f406e3d) + +## Accessing the Managed API Through the apiman API Gateway, Watching the Policies at Runtime + +Thanks for hanging in there! The set up is done. Now, we can fire up the client app and watch the policies in action as they are applied at runtime by the API Gateway, for example: + +Open the client app, and enter the URL for the managed API [http://localhost:8080/apiman-gateway/ACMEServices/echo/1.0?apikey=c374c202-d4b3-4442-b9e4-c6654f406e3d](http://localhost:8080/apiman-gateway/ACMEServices/echo/1.0?apikey=c374c202-d4b3-4442-b9e4-c6654f406e3d) + +What happens first is that the authentication policy is applied and a login dialog is then displayed: + +![Screenshot 41](/blog/images/2015-01-09/Screenshot-41.png) + +Enter the username and password (user1/password) that we defined when we created the authentication policy to access the API. The fact that you are seeing this dialog confirms that you are accessing the managed API and are not accessing the API directly. + +When you send a GET request to the API, you should see a successful response: + +![Screenshot 40](/blog/images/2015-01-09/Screenshot-40.png) + +So far so good. Now, send 10 more requests and you will see a response that looks like this as the gold plan rate limit is exceeded: + +![Screenshot 39](/blog/images/2015-01-09/Screenshot-39.png) + +And there it is. Your gold plan has been exceeded. Maybe next time you'll spend a little more and get the platinum plan! ;-) + +## Wrap-up + +Let's recap what we just accomplished in this demo: + +* We installed apiman 1.0 onto a WildFly server instance. +* We used git to download and maven to build a sample REST client. +* As an API provider, we created an organization, defined policies based on API use limit rates and user authentication, and a plan, and assigned them to an API. +* As an API consumer, we searched for and found that API, and assigned it to a client app. +* As a client app, we accessed the API and observed how the API Gateway managed the API. + +And, if you note, in the process of doing all this, the only code that we had to write or build was for the client app. We were able to fully configure the API, policies, plans, and the client app in the API Manager UI. + +## What's Next? + +In this post, we've only scratched the surface of API Management with apiman. To learn more about apiman, you can explore its website here: http://www.apiman.io/ + +Join the project mailing list here: [https://lists.jboss.org/mailman/listinfo/apiman-user](https://lists.jboss.org/mailman/listinfo/apiman-user) + +And, better still, get involved! Contribute bug reports or feature requests. Write about your own experiences with apiman. Download the apiman source code, take a look around, and contribute your own additions. apiman 1.0 was just released, there's no better time to join in and contribute! + +## Downloads Used in this Article + +* REST Client [http://restclient.net/](http://restclient.net/) FireFox Add-On - [https://addons.mozilla.org/en-US/firefox/addon/restclient/versions/2.0.3](https://addons.mozilla.org/en-US/firefox/addon/restclient/versions/2.0.3) +* Echo API source code - [https://github.com/apiman/apiman-quickstarts](https://github.com/apiman/apiman-quickstarts) +* apiman 1.0 - [http://downloads.jboss.org/apiman/1.0.0.Final/apiman-distro-wildfly8-1.0.0.Final-overlay.zip](http://downloads.jboss.org/apiman/1.0.0.Final/apiman-distro-wildfly8-1.0.0.Final-overlay.zip) +* WildFly 8.2.0 - [http://download.jboss.org/wildfly/8.2.0.Final/wildfly-8.2.0.Final.zip](http://download.jboss.org/wildfly/8.2.0.Final/wildfly-8.2.0.Final.zip) +* Git - [http://git-scm.com](http://git-scm.com) +* Maven - [http://maven.apache.org](http://maven.apache.org) + +## References + +* [http://www.apiman.io/](http://www.apiman.io/) +* apiman tutorial videos - [http://vimeo.com/user34396826](http://vimeo.com/user34396826) +* [http://www.softwareag.com/blog/reality_check/index.php/soa-what/what-is-api-management/](http://www.softwareag.com/blog/reality_check/index.php/soa-what/what-is-api-management/) +* [http://keycloak.jboss.org/](http://keycloak.jboss.org/) diff --git a/_blog-src/_posts/2015-01-09-impatient-new-user.markdown b/_blog-src/_posts/2015-01-09-impatient-new-user.markdown index 78153691e..da66edcdb 100644 --- a/_blog-src/_posts/2015-01-09-impatient-new-user.markdown +++ b/_blog-src/_posts/2015-01-09-impatient-new-user.markdown @@ -4,6 +4,7 @@ title: "An Impatient New User's Introduction to API Management with JBoss apima date: 2015-01-09 09:15:00 author: len_dimaggio categories: introduction overview +newUrl: 2015-01-09-impatient-new-user-redux --- Software application development models are evolutionary things. New technologies are always being created diff --git a/_blog-src/_posts/2015-03-06-custom-policies-redux.markdown b/_blog-src/_posts/2015-03-06-custom-policies-redux.markdown new file mode 100644 index 000000000..04a92c25c --- /dev/null +++ b/_blog-src/_posts/2015-03-06-custom-policies-redux.markdown @@ -0,0 +1,191 @@ +--- +layout: post +title: "Customizing JBoss apiman Through Policy Plugins" +date: 2015-03-06 10:22:00 +author: len_dimaggio +categories: plugins policies development maven +oldUrl: 2015-03-06-custom-policies +--- + +This is the second in a series of articles exploring API management with JBoss apiman. The first article +was a general introduction to apiman for impatient users where in only 10 minutes we installed apiman, +created users and organizations, and APIs, policies, contracts, and client apps. In this article, +we'll take the first step toward customizing apiman by creating new plugins to implement API policies. + + + +The major new feature added to release 1.0.2 of apiman [http://www.apiman.io/](http://www.apiman.io/) is the ability to extend its features through a custom plugin framework. Since policies perform the most important apiman runtime operations, plugins that enable you to create new policies are the first type of plugins to be supported. + +In this article, we'll examine all the steps that you must perform to create a new policy plugin, and then import it into apiman and configure an API to put it into use. + +## Prerequisites + +For this article, we'll assume that you have completed all the steps in the first article in this series. The first article guides even the most impatient user through installing and using apiman. + +## Accessing the Example Plugins + +Like all JBoss software, apiman provides functioning example code that you can use as a starting point for your own plugins. The easiest way to create and package an apiman is as a standard maven project packaged as a .war file. + +To download a copy of the example plugins, execute this git command: + + git clone https://github.com/apiman/apiman-plugins + +When the git clone operation completes, you'll have the source code for multiple example plugins. The exact set of plugins that you have downloaded may change, depending on when you download them, as more examples are always being added. For the purposes of this article, we'll focus on the "config-policy" example plugin. This plugin demonstrates how a plugin can be used to set the value of properties in a message being processed by an API. Specifically, this plugin defines properties in the request and response headers and enables you to set their values to "true." + +## Requirements for a Plugin Implementation + +The easiest way that an apiman policy plugin can be build and packaged is as a standard maven project packaged as a .war file. There are just a few modifications that are required to convert a .war into a plugin. + +Let's take a closer look at the files and directories that comprise the apiman config-policy plugin, and the changes that are needed to implement a plugin: + + ├---pom.xml + └---src + └---main + ├---apiman + │ ├---plugin.json + │ └---policyDefs + │ ├---config-policyDef.json + │ └---schemas + │ └---config-policyDef.schema + └---java + └---io + └---apiman + └---plugins + └---config_policy + ├---ConfigBean.java + └---ConfigPolicy.java + +The most obvious difference is the addition of the "apiman" directory. This directory is used to contain the configuration files for the plugin. (In other words, the files that make the project a plugin.) The only project-wide configuration change that you have to make is to modify the plugin's maven pom.xml file to include the apiman directory when the project is built. The following lines are added to the plugin's pom.xml file: + +{% highlight xml %} + + src/main/apiman + META-INF/apiman + true + +{% endhighlight %} + +The result of these statements in the pom.xml file is that the contents of the apiman directory are included in the project build's META-INF directory. (We'll take a look at this later when we build the plugin project.) Setting filtering to true enables maven property expansion during the creation of the plugin war file. +Configuration files for the plugin are contained in the apiman directory. The primary configuration file is the "plugin.json" file. This file is required for all apiman plugins, regardless of the plugin type. The meta-data contained in this file describes the plugin and is displayed in the API Manager UI. + +Since our example is contributing a policy, it must contain a JSON file that defines the policy. This JSON file is contained in the apiman/policyDefs directory and is named "config-policyDef.json." This file defines the following fields for the policy: + +* *id* - A unique identifier for the policy +* *name* - A user friendly (in other words, a human readable) name for the policy. This policy name is displayed in the API Manager UI +* *description* - A description of the policy +* *policyImpl* - This is the fully qualified classname name of the Java class that actually implements the policy. This value must be properly formatted to include information about the plugin, including placeholders for maven properties, for example, project version. +* *icon* - This is the name of a Font Awesome icon [http://fortawesome.github.io/Font-Awesome/](http://fontawesome.github.io/Font-Awesome/) that is displayed for the Policy in the API Manager UI. +* *formType* - The type of policy configuration UI form. Our example uses JsonSchema. +* *form* - This is a relative path to the policy configuration UI form contained in the plugin. Our examples uses the JSON Schema that defines the configuration data format. (More on this file in a minute. + +In our example, the config-policyDef.json looks like this: + +{% highlight json %} +{ + "id" : "config-policy", + "name" : "Config Policy", + "description" : "A policy used to showcase policy configuration.", + "policyImpl" "plugin:${project.groupId}:${project.artifactId}:${project.version}:${project.packaging}/io.apiman.plugins.config_policy.ConfigPolicy", + "icon" : "sliders", + "formType" : "JsonSchema", + "form" : "schemas/config-policyDef.schema" +} +{% endhighlight %} + +We mentioned that since our example uses the JSON schema [http://json-schema.org/documentation.html](http://json-schema.org/documentation.html), we have to also define the configuration data format. This is done in the policyDefs/schemas/config-policyDef.schema file. This file defines the format used in the policy configuration file data and is used by the API Manager UI to generate a form that is used to fill in the values to be used to configure the policy. In our example, the policy's JSON schema defines two properties: requestHeader and responseHeader. + +{% highlight json %} +{ + "title" : "Configure HTTP Headers", + "description" : "Set the HTTP request header to populate with the value 'true' when the request is made. Also set the HTTP response header to populate with the value 'true' after the response is received from the back-end API.", + "type" : "object", + "properties": { + "requestHeader": { + "title" : "Request Header", + "type" : "string", + "minLength" : 1, + "maxLength" : 64 + }, + "responseHeader": { + "title" : "Response Header", + "type" : "string", + "minLength" : 1, + "maxLength" : 64 + } + } +} +{% endhighlight %} + +That finishes the description of the policy's configuration files. To complete the policy plugin, the example also requires the Java implementation for the policy itself. The policy implementation is contained in the src/main/java/io/apiman/plugins/config_policy/ConfigPolicy.java file. The policy is very simple as it merely appends a header to the http request and response. + +Java policy classes must implement the apiman IPolicy interface. This example takes that a step further by actually extending the io.apiman.gateway.engine.policies.AbstractMappedPolicy class. By doing so, the policy Java code can take advantage of the AbstractMappedPolicy's class use of the Jackson (https://github.com/FasterXML/jackson) JSON parser to parse the policy configuration data into a Java bean. (In this example, the bean is implemented in src/main/java/io/apiman/plugins/config_policy/ConfigBean.java.) If the policy implemented the IPolicy interface, instead of extending AbstractMappedPolicy, then the policy Java class would have to implement its own parser. + +## Building the Plugin and Installing it into the Maven Repo + +Building the plugin with maven is easy. Just execute this command from the directory that contains the plugin's pom.xml file. + + mvn install + +In case you're wondering why, we're installing the plugin into the maven repo. The answer is simply that in the current release of apiman, the only supported install path is from the maven repo. Future releases of apiman will likely support additional installation paths. + +## Installing a Plugin into apiman + +In apiman, a policy plugin, once installed, is available on a system-wide basis. Accordingly, plugins can only be installed by an admin user. After you login as admin, you'll see this in the admin UI: + +![System Administration](/blog/images/2015-03-06/apiman-1.png) + +After selecting "Manage Plugins," you'll see a screen that looks like this: + +![Plugins](/blog/images/2015-03-06/apiman-2.png) + +And, if you then select "Add Plugin," you'll see this screen: + +![Add Plugin](/blog/images/2015-03-06/apiman-3.png) + +The GroupId, ArtifactId, and Version information is all available in the example plugin's pom.xml file: + +* *GroupId*: io.apiman.plugins +* *ArtifactId*: apiman-plugins-config-policy +* *Version*: 1.0.3-SNAPSHOT + +After you enter this information for the plugin and click on "Add Plugin," you'll see this displayed in the UI: + +![Plugins](/blog/images/2015-03-06/apiman-4.png) + +Congratulations! The plugin is installed and is ready to be used! Let's add it to an API and see it in action. + +## Using the Installed Plugin + +First, we have to log out of the admin account in the Admin UI and then log back in as the "serprov" API provider. Then, select our "echo" API, and create a new version of the API, based on the original version of the API: + +![New API Version](/blog/images/2015-03-06/apiman-6.png) + +And, when you add a new policy to the API, you'll see the example config API that we just installed: + +![Add Policy](/blog/images/2015-03-06/apiman-5.png) + +When you select the Config Policy, you'll be presented with a dialog where you can specify the values for the two properties defined in the policy: + +![Add Policy](/blog/images/2015-03-06/apiman-7.png) + +Let's fill in some easy to remember values: + +![Add Policy](/blog/images/2015-03-06/apiman-8.png) + +After adding the policy, you'll see it displayed in the policies defined for the API: + +![Add Policy](/blog/images/2015-03-06/apiman-9.png) + +Then publish the API. In order to consume the API, login to the API Manager UI as the client app developer "appdev", and create a new client app that uses the new API. (We covered the creation of new client apps in detail in the first article in this series) + +And when the API is invoked, you'll see something like this: + +![REST Client](/blog/images/2015-03-06/apiman99.png) + +And this: + +![REST Client](/blog/images/2015-03-06/apiman100.png) + +## In Conclusion + +OK, let's recap. apiman is a rapidly growing and developing project. Each new release brings new features. In release 1.0.2, it became possible for users to contribute custom policies into their apiman installation through the API Manager UI. diff --git a/_blog-src/_posts/2015-03-06-custom-policies.markdown b/_blog-src/_posts/2015-03-06-custom-policies.markdown index 17fb4d070..ac51dfb5b 100644 --- a/_blog-src/_posts/2015-03-06-custom-policies.markdown +++ b/_blog-src/_posts/2015-03-06-custom-policies.markdown @@ -4,6 +4,7 @@ title: "Customizing JBoss apiman Through Policy Plugins" date: 2015-03-06 10:22:00 author: len_dimaggio categories: plugins policies development maven +newUrl: 2015-03-06-custom-policies-redux --- This is the second in a series of articles exploring API management with JBoss apiman. The first article diff --git a/_blog-src/_posts/2015-05-08-authorization-redux.markdown b/_blog-src/_posts/2015-05-08-authorization-redux.markdown new file mode 100644 index 000000000..0b36332ca --- /dev/null +++ b/_blog-src/_posts/2015-05-08-authorization-redux.markdown @@ -0,0 +1,66 @@ +--- +layout: post +title: "Authorization: good god, what is it good for?" +date: 2015-05-08 13:15:15 +author: eric_wittmann +categories: authorization authentication policy +oldUrl: 2015-05-08-authorization +--- + +Quite a bit, actually. :) + +I want to talk about how Authorization currently works in apiman, because it's +a little bit more loosely coupled than you might expect. Note that at some +point in the future we're going to be renovating how policies are defined and +configured in the API Manager UI. But until then, you can refer to this blog +post for an overview of how to configure Authorization! + + + +I won't bury the lead - the key to getting Authorization to work is understanding +that it *only* works together with Authentication. First you must add and +configure a compatible *Authentication* policy, which will be responsible for +extracting the user's roles and passing them along to the Authorization policy. + +## Define your terms, sir! +Let's make sure we're on the same page with respect to terminology, shall we? + +* **Authentication**: the act of validating that a user is who she claims to be, by checking provided credentials against some source of identity. Examples include BASIC Authentication and OAuth2. +* **Authorization**: the act of ensuring that the authenticated user has *permission* to perform the requested action or view the requested data. Typically involves checking that the user possesses one or more required roles. + +## How does this work in apiman? + +I'm glad you asked. In apiman we have split these two functions out into separate policies. This allows us to use the same Authorization policy regardless of what type of Authentication is being used. + +Basically you need to do the following two things: + +1. Add and configure an Authentication policy such as the BASIC Authentication Policy or the Keycloak OAuth2 Authentication Policy +1. Add and configure an Authorization Policy. + +That's it in a nutshell! + +## Give me more details! + +OK, OK. If you're reading this you probably know the apiman basics - how to create Organizations and APIs and whatnot. If not, I would recommend you check out the [User Guide](http://www.apiman.io/latest/user-guide.html) or the [Tutorials](http://www.apiman.io/latest/tutorials.html). + +Once you have an API that you want to configure, go ahead and add a new policy. Choose, for example, the *BASIC Authentication Policy* and configure it as seen in the following screenshot: + +![Example BASIC Authentication configuration](/blog/images/2015-05-08/basic-auth-config.png) + +Once you've added that policy, you can add the Authorization Policy - make sure they are in the proper order, since the Authentication policy must execute first. Configure the Authorization Policy however you like, using roles appropriate for your users. For example, it might look like this: + +![Example Authorization configuration](/blog/images/2015-05-08/authorization-config.png) + +Once all is said and done, you should have two (at least) policies configured for your API. It might look something like this in the UI: + +![Example policy list](/blog/images/2015-05-08/auth-policies.png) + +If you follow those steps, everything should work out alright for you! The Authorization Policy is capable of being quite fine-grained. You can configure role based access via custom resource location regular expressions and HTTP verb(s). If all you want is a global required role to access your API, that's easy too: + +* **Resource Path**: /.* +* **Verb/action**: * +* **Required Role**: + +Good luck and come find us on the mailing list or IRC if you have any trouble! + +/post diff --git a/_blog-src/_posts/2015-05-08-authorization.markdown b/_blog-src/_posts/2015-05-08-authorization.markdown index 04896820a..4e01146b5 100644 --- a/_blog-src/_posts/2015-05-08-authorization.markdown +++ b/_blog-src/_posts/2015-05-08-authorization.markdown @@ -4,7 +4,9 @@ title: "Authorization: good god, what is it good for?" date: 2015-05-08 13:15:15 author: eric_wittmann categories: authorization authentication policy +newUrl: 2015-05-08-authorization-redux --- + Quite a bit, actually. :) I want to talk about how Authorization currently works in apiman, because it's diff --git a/_blog-src/_posts/2015-05-09-policy-testing-redux.markdown b/_blog-src/_posts/2015-05-09-policy-testing-redux.markdown new file mode 100644 index 000000000..5366e65bd --- /dev/null +++ b/_blog-src/_posts/2015-05-09-policy-testing-redux.markdown @@ -0,0 +1,205 @@ +--- +layout: post +title: "A great way to test your custom apiman policy!" +date: 2015-05-09 09:07:45 +author: eric_wittmann +categories: policy junit testing +newUrl: 2015-05-09-policy-testing +--- + +If you have tried creating your own custom apiman policy, you may have had a little bit of +difficulty creating useful junit tests for it. Many policies require various apiman +runtime components to be available. It can be super annoying trying to use something like +mockito to create mock versions of everything your policy needs. Even for simple policies +you really just want a quick and effective way to test the implementation within a +reasonably "real world" harness. + +Well you've probably guessed by now that I'm about to show you how it's done! (OK fine, +how it *will* be done in the next release of apiman - 1.1.3.Final) + + + +In this post I'll explain (and show!) you how to write a unit test for your apiman +policy, using the new Policy Tester junit framework we've created. + +## First you need a custom policy! + +If you haven't created a custom apiman policy yet, have a look at the +[Developer Guide](http://www.apiman.io/latest/developer-guide.html#_plugins) to +learn how. + +So for example, let's say you've created your own simple custom policy class and it +looks like this: + +{% highlight java %} +public class MySimplePolicy implements IPolicy { + + @Override + public Object parseConfiguration(String jsonConfiguration) throws ConfigurationParseException { + return jsonConfiguration; + } + + @Override + public void apply(ApiRequest request, IPolicyContext context, Object config, + IPolicyChain chain) { + request.getHeaders().put("X-MTP-Header", "Hello World"); + if (request.getHeaders().get("X-Fail-Test") != null) { + IPolicyFailureFactoryComponent failureFactory = context.getComponent(IPolicyFailureFactoryComponent.class); + chain.doFailure(failureFactory.createFailure(PolicyFailureType.Other, 42, "Failure")); + } else { + chain.doApply(request); + } + } + + @Override + public void apply(ApiResponse response, IPolicyContext context, Object config, + IPolicyChain chain) { + response.getHeaders().put("X-MTP-Response-Header", "Goodbye World"); + chain.doApply(response); + } +} +{% endhighlight %} + +## OK I've got a policy, how do I test it? + +Now that you've got your policy, you need a quick and effective way to test it. I also +think it's important for your test to run quickly and for you to be able to easily set +breakpoints to debug the code. We explored using [Arquillian](http://arquillian.org/) +to configure and publish an API with the custom policy to a running WildFly server. +It actually works remarkably well, but the overhead of firing up a WildFly server just +to test a single policy seemed excessive. That work will likely lead into a separate +testing effort focused on testing larger integration scenarios. + +OK enough - let's get to the test! The first thing you need is to pull the Policy +Tester dependency into your project's pom.xml: + +{% highlight xml %} + + io.apiman + apiman-test-policies + 1.1.2-SNAPSHOT + test + +{% endhighlight %} + +Great - now just create a new junit test and make sure it extends the `ApimanPolicyTest` +base test class. In that junit test you'll need to sprinkle in a few annotations +provided by the apiman Policy Testing framework. At a minimum you will need to +include the `@TestingPolicy` and `@Configuration` annotations. Both of these annotations +can be specified at either the *Class* or *Method* level. The former tells the testing +framework which policy is being tested. The latter describes the policy configuration +that should be used for the test. + +Just look at the example, already: + +{% highlight java %} +@TestingPolicy(MySimplePolicy.class) +public class MyTestPolicyTest1 extends ApimanPolicyTest { + + @Test + @Configuration("{}") + public void testGet() throws Throwable { + // Send a test HTTP request to the API (resulting in executing the policy). + PolicyTestResponse response = send(PolicyTestRequest.build(PolicyTestRequestType.GET, "/some/resource") + .header("X-Test-Name", "testGet")); + + // Now do some assertions on the result! + Assert.assertEquals(200, response.code()); + EchoResponse entity = response.entity(EchoResponse.class); + Assert.assertEquals("GET", entity.getMethod()); + Assert.assertEquals("/some/resource", entity.getResource()); + Assert.assertEquals("testGet", entity.getHeaders().get("X-Test-Name")); + // Assert the request header that was added by the policy + Assert.assertEquals("Hello World", entity.getHeaders().get("X-MTP-Header")); + // Assert the response header was added by the policy + Assert.assertEquals("Goodbye World", response.header("X-MTP-Response-Header")); + } + +} +{% endhighlight %} + +## So what's going on here? + +Let me tell you! For each test method in your junit test, we'll actually spin up a fully +functional apiman API Gateway. We'll also publish a test API that's configured with +your custom policy (and using the policy configuration you specified in the `@Configuration` +annotation). After that, it's a simple matter of sending one or more simulated HTTP +requests to the gateway. You do that by sending a `PolicyTestRequest` to the `send` method. +Easy peasy! + +Note that it's pretty easy to create a `PolicyTestRequest` - there's a nice little fluent +builder you can use to create it. The builder allows you to set the HTTP verb, the resource +path, and any HTTP headers. + +## What about the back-end API? + +Yeah that's a good point. Assuming your policy doesn't produce a failure, the API Gateway +we're using for the test needs to "invoke" a back-end API and return the result. We +simulate this rather than actually going out and making a REST request. By default, we +create a simple Echo back-end API which bundles up all the information in the REST +request (including anything your policy may have added to the request) and builds a JSON +response that includes all that information. This is handy because it allows you to +verify that, for example, any HTTP headers your policy added to the request actually +made it through to the back-end API. + +Now are you ready for an advanced topic? If not I understand, you can just hit the Back +button on your browser! + +Still here? Great! Another thing you can do is actually provide your own simulated +back-end API. This is necessary sometimes when your policy does something +specific with, for example, the API response payload. You may actually need your +test to respond in a certain way. To accomplish this all you need to do is use the +`@BackEndApi` annotation, providing a *Class* that implements the +`IPolicyTestBackEndApi` interface. You do that, and we'll use your simulated +back end API for the test instead of the echo API! :) + +What would that look like? Something like this: + +{% highlight java %} +@TestingPolicy(MySimplePolicy.class) +public class MyTestPolicyTest1 extends ApimanPolicyTest { + + @Test + @Configuration("{}") + @BackEndApi(MyCustomBackEndApiImpl.class) + public void testGet() throws Throwable { + // Send a test HTTP request to the API (resulting in executing the policy). + PolicyTestResponse response = send(PolicyTestRequest.build(PolicyTestRequestType.GET, "/some/resource") + .header("X-Test-Name", "testGet")); + + // Now do some assertions on the result! + MyCustomBackEndApiResponseBean entity = response.entity(MyCustomBackEndApiResponseBean.class); + + // Do some more assertions here using the entity from above! + } + +} +{% endhighlight %} + +And then perhaps your custom back end implementation class might look like this: + +{% highlight java %} + +public class MyCustomBackEndApiImpl implements IPolicyTestBackEndApi { + @Override + public PolicyTestBackEndApiResponse invoke(ApiRequest request, byte[] requestBody) { + // Create a valid API response for this request, and then configure it. + ApiResponse apiResponse = new ApiResponse(); + apiResponse.setCode(200); + apiResponse.setMessage("OK"); + apiResponse.getHeaders().put("Date", new Date().toString()); + apiResponse.getHeaders().put("Server", "apiman.policy-test"); + apiResponse.getHeaders().put("Content-Type", "text/plain"); + // Let's respond with a classic "Hello World" for the response body + String body = "Hello World"; + PolicyTestBackEndApiResponse response = new PolicyTestBackEndApiResponse(apiResponse, body); + return response; + } +} + +{% endhighlight %} + + +Alright - if you made it this far thanks for reading!! + +/post diff --git a/_blog-src/_posts/2015-05-09-policy-testing.markdown b/_blog-src/_posts/2015-05-09-policy-testing.markdown index ed607fb92..54e65030f 100644 --- a/_blog-src/_posts/2015-05-09-policy-testing.markdown +++ b/_blog-src/_posts/2015-05-09-policy-testing.markdown @@ -4,7 +4,9 @@ title: "A great way to test your custom apiman policy!" date: 2015-05-09 09:07:45 author: eric_wittmann categories: policy junit testing +newUrl: 2015-05-09-policy-testing-redux --- + If you have tried creating your own custom apiman policy, you may have had a little bit of difficulty creating useful junit tests for it. Many policies require various apiman runtime components to be available. It can be super annoying trying to use something like diff --git a/_blog-src/_posts/2015-05-19-rest-api-redux.markdown b/_blog-src/_posts/2015-05-19-rest-api-redux.markdown new file mode 100644 index 000000000..c6c20b6de --- /dev/null +++ b/_blog-src/_posts/2015-05-19-rest-api-redux.markdown @@ -0,0 +1,209 @@ +--- +layout: post +title: "The JBoss apiman API Manager REST API" +date: 2015-05-19 11:00:00 +author: len_dimaggio +categories: rest api automation +oldUrl: 2015-05-19-rest-api +--- + +In this, the third article in our series on apiman, JBoss' new open source API Management framework, we'll examine apiman’s API Manager REST API. apiman’s Management UI utilizes this API in the implementation for all of its user-visible features, and you can also use the same API to automate tasks with apiman. + + + +## Introduction + + It's inevitable that, after you work with a product's UI for a while that you encounter tasks that are better suited to a scripting or batch interface. For example, if you have to perform a similar task for a large of related data items, the time that it can require to perform these tasks through an interactive UI can be prohibitive. Also, it's easy for repetitive tasks to become error prone as you can lose focus, even if you are working in a well designed and easy to use interface such as apiman. + +One solution to this problem is to augment the UI with a command line or scripting interface. This can lead to a whole separate set of issues if the new interface is built on a different set of underlying routines than the UI. A better approach to allow access to the same routines in which the UI is constructed. This approach removes any duplication, and also enables you to replicate manual UI based tasks with automated or scripted tools. + +JBoss apiman follows this second approach with its REST interface. All the services provided by apiman in its Management UI are directly supported in the API Manager REST API. You can also directly access these same services through the REST API. + +## Prerequisites + +Like a lot of things with JBoss open source software, installing the REST API is easy. In fact, if you have apiman installed, then you already have the REST API installed. (You can’t get much easier than that!) + +We covered installing apiman in the first article in this series (see: http://java.dzone.com/articles/impatient-new-users), so we won't repeat that information here. A minimal set of install instructions are always available on the apiman site (http://www.apiman.io/latest/). The current set of instructions as of this writing are: + +{% highlight bash %} +mkdir ~/apiman-1.1.2.Final +cd ~/apiman-1.1.2.Final +wget http://download.jboss.org/wildfly/8.2.0.Final/wildfly-8.2.0.Final.zip +wget http://downloads.jboss.org/apiman/1.1.2.Final/apiman-distro-wildfly8-1.1.2.Final-overlay.zip +unzip wildfly-8.2.0.Final.zip +unzip -o apiman-distro-wildfly8-1.1.2.Final-overlay.zip -d wildfly-8.2.0.Final +cd wildfly-8.2.0.Final +./bin/standalone.sh -c standalone-apiman.xml +{% endhighlight %} + +Now that our apiman server is up and running, we can start to access the API Manager REST API. However, before we start placing calls to APIs through the REST API, let’s take a look at how the API is organized. + +##The Organization of the API + +The documentation for the apiman REST API is available (for free, of course), here: http://www.apiman.io/latest/api-manager-restdocs.html + +The services and their endpoints represented in the API are divided into these groups: + +* actions - The actions endpoint (http://localhost:8080/apiman/actions/) enables you to execute actions for apiman entities (such as plans, APIs, applications, etc.) + +* system/status - The system/status endpoint (http://localhost:8080/apiman/system/status) enables you to query the current state of the apiman system. + +* currentuser - The currentuser endpoint (http://localhost:8080/apiman/currentuser/info) enables you to obtain or update information about the current user. This information is related to the user’s applications, APIs, organizations, etc. + +* gateways - The gateways endpoint (http://localhost:8080/apiman/gateways/) enables you to obtain information about an API Gateway, and to delete or create new gateways. + +* organizations - The organizations endpoint (http://localhost:8080/apiman/organizations/) enables you to obtain information about existing organizations and to create new organizations. + +* permissions - The permissions endpoint (http://localhost:8080/apiman/permissions/) enables you to obtain information about user’s permissions. + +* plugins - The plugins endpoint (http://localhost:8080/apiman/plugins/) enables you to obtain information about installed plugins, and to install new plugins. + +* policyDefs - The policyDefs endpoint (http://localhost:8080/apiman/policyDefs/) enables you to obtain information about existing policy definitions, and to define new policy definitions. + +* roles - The roles endpoint (http://localhost:8080/apiman/roles/) enables you to obtain information about existing roles, update roles, and delete roles. + +* search - The search endpoint (http://localhost:8080/apiman/search/) enables you to search for applications, organizations, or APIs. + +* users - The users endpoint (http://localhost:8080/apiman/users/) enables you to search for information about users, including their applications and APIs. + +Within each group, GET operations are defined to return information, and GET and POST operations are defined to make changes to apiman elements. Data passed to and returned from services through the API is in the form of JSON along with a return code. + +##Accessing APIs in the API Manager REST API + + The best way to learn about the API Manager REST API is to see it in action. Since these are REST APIs, it’s easy to access them. For example, we should be able to access the system status service with a simple GET operation at this endpoint: + +http://localhost:8080/apiman/system/status + +Let’s try this with curl. If we execute the following command, we should see the current system status: + + curl -X GET http://localhost:8080/apiman/system/status + +Well, that error is not exactly what we expected. There was no output. + +What went wrong? What’s missing? The answer is that our call to the API was missing authorization. In the same way that a user must login and be authorized to use the apiman Management UI, calls to the REST API must be authorized. + +For our example, we’ll keep things simple and stick to using basic authorization. (We’ll take a more extensive look at apiman and security in a later article in this series.) + +In order to resolve this failure, we have to send a properly encoded basic authorization header with every request you make. In Java8, we can generate a key by base64 encoding this string for the OOTB admin username and password: admin:admin123! with this statememt: + + base64encode(concat('admin', ':', 'admin123!')) + +This yields a key with a value of: YWRtaW46YWRtaW4xMjMh + +Now, let’s try that curl command again, but this time, we’ll include the key in the authorization header: + + $ curl -H "Authorization: Basic YWRtaW46YWRtaW4xMjMh" + http://localhost:8080/apiman/system/status + +And the result is: + + {"up":true,"version":"1.1.2-SNAPSHOT"} + +As we mentioned earlier in this article, the responses returned by calls to the REST API are in in the form of JSON. In the case of our call to the http://localhost:8080/apiman/system/status endpoint, the expected format of the response is: + +{% highlight json %} +{ + version : string + up : boolean +} +{% endhighlight %} + +Let’s carry on by looking at a more extensive example, where we use the REST API to automate a task that would be tedious if performed in the apiman Management UI. + +##A Larger Example + +Let’s say that you want to create multiple new organizations. You could of course manually enter these into the apiman Management UI. But, if you have a large number of organizations, for example, one for each of the countries in the EU, or each of the states in the USA, this would be a tedious and error prone task. This is an ideal candidate task for automation with the REST API. + +The coding for this example is simple. All you have to do is account for the encoding of the authorization to access the API Manager REST API, and pass the information related to each organization that you create to this endpoint: http://localhost:8080/apiman/organizations + +Here’s an example program with an ice hockey flavor - the highlights are noted below: + +{% highlight java linenos %} +package apimanExample; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Base64; + +public class SimplePutOrg { + + public static void main(String[] args) throws Exception { + + String [ ] [ ] originalSix = { + { "Boston", "Chicago", "Detroit", "Montreal", "New York", "Toronto"}, + { "Bruins", "BlackHawks", "Red Wings", "Canadiens", "Rangers", "Maple Leafs"} + }; + for (int i = 0; i < 6; i++) { + System.out.println ("Creating new apiman org for: " + originalSix [0][i] + ":" + originalSix [1][i]); + System.out.println ("Return code = " + createNewOrg (originalSix [0][i], originalSix [1][i])); + } + } + + private static int createNewOrg (String newOrgName, String newOrgDescription) throws IOException { + URL url = new URL("http://localhost:8080/apiman/organizations"); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + + Base64.Encoder encoder = Base64.getEncoder(); + String normalString = "admin:admin123!"; + String encodedString = encoder.encodeToString(normalString.getBytes(StandardCharsets.UTF_8)); + + connection.setRequestProperty("Authorization", "Basic " + encodedString); + connection.setRequestMethod("POST"); + connection.setDoOutput(true); + connection.setRequestProperty("Content-Type", "application/json"); + connection.setRequestProperty("Accept", "application/json"); + + OutputStreamWriter osw = new OutputStreamWriter(connection.getOutputStream()); + osw.write(String.format("{\"name\":\"" + newOrgName + " a new org\",\"description\":\"" + newOrgDescription + "\"}")); + osw.flush(); + osw.close(); + + return connection.getResponseCode(); + } +} +{% endhighlight %} + +Code highlights: + +* Lines 13-16: Here's where we define the test data. For this example, we'll use the National Hockey League's "original 6" teams. +* Line 24: Here's the URL for the service to which we'll connect to create the new organizations. +* Lines 27-29 - Here's where we set up the encoding for the BASIC authorization. +* Lines 31-35 - And here's where we create the HttpURLConnection that we will use to connect to the service. +* Line 32: Note that we will be performing a POST operation. +* Lines 37-40 - And finally, here's where we connect to the service and send our POST requests to create the new organizations. + +When we run this example, the following output indicates that the calls to the service through the REST API were successful, based on the return code of 200: + + Creating new apiman org for: Boston:Bruins + Return code = 200 + Creating new apiman org for: Chicago:BlackHawks + Return code = 200 + Creating new apiman org for: Detroit:Red Wings + Return code = 200 + Creating new apiman org for: Montreal:Canadiens + Return code = 200 + Creating new apiman org for: New York:Rangers + Return code = 200 + Creating new apiman org for: Toronto:Maple Leafs + Return code = 200 + +And - here’s the server output that tracks the creation of the new organizations: + + 21:17:53,205 INFO [stdout] (default task-19) Created organization Boston a new org: OrganizationBean [id=Bostonaneworg, name=Boston a new org, description=Bruins, createdBy=admin, createdOn=Sun May 17 21:17:53 GMT-05:00 2015, modifiedBy=admin, modifiedOn=Sun May 17 21:17:53 GMT-05:00 2015] + 21:17:53,233 INFO [stdout] (default task-21) Created organization Chicago a new org: OrganizationBean [id=Chicagoaneworg, name=Chicago a new org, description=BlackHawks, createdBy=admin, createdOn=Sun May 17 21:17:53 GMT-05:00 2015, modifiedBy=admin, modifiedOn=Sun May 17 21:17:53 GMT-05:00 2015] + 21:17:53,253 INFO [stdout] (default task-23) Created organization Detroit a new org: OrganizationBean [id=Detroitaneworg, name=Detroit a new org, description=Red Wings, createdBy=admin, createdOn=Sun May 17 21:17:53 GMT-05:00 2015, modifiedBy=admin, modifiedOn=Sun May 17 21:17:53 GMT-05:00 2015] + 21:17:53,275 INFO [stdout] (default task-25) Created organization Montreal a new org: OrganizationBean [id=Montrealaneworg, name=Montreal a new org, description=Canadiens, createdBy=admin, createdOn=Sun May 17 21:17:53 GMT-05:00 2015, modifiedBy=admin, modifiedOn=Sun May 17 21:17:53 GMT-05:00 2015] + 21:17:53,295 INFO [stdout] (default task-27) Created organization New York a new org: OrganizationBean [id=NewYorkaneworg, name=New York a new org, description=Rangers, createdBy=admin, createdOn=Sun May 17 21:17:53 GMT-05:00 2015, modifiedBy=admin, modifiedOn=Sun May 17 21:17:53 GMT-05:00 2015] + 21:17:53,316 INFO [stdout] (default task-29) Created organization Toronto a new org: OrganizationBean [id=Torontoaneworg, name=Toronto a new org, description=Maple Leafs, createdBy=admin, createdOn=Sun May 17 21:17:53 GMT-05:00 2015, modifiedBy=admin, modifiedOn=Sun May 17 21:17:53 GMT-05:00 2015] + +And finally, here are the organizations as displayed in the apiman Management UI: + +![new organizations](/blog/images/2015-05-19/new-organizations.png) + +(It’s been a tough year for Boston Bruins’ fans. It’s nice to see the team listed first, even if it’s just an alphabetic list. ;-) + +##In Conclusion + +The architecture of the apiman Management UI is that the UI is built on top of a REST API. This architecture makes it possible for you to directly access the services exposed by the API, and enables you to automate the tasks that you perform in the UI. diff --git a/_blog-src/_posts/2015-05-19-rest-api.markdown b/_blog-src/_posts/2015-05-19-rest-api.markdown index df4a7c10f..51298a9a9 100644 --- a/_blog-src/_posts/2015-05-19-rest-api.markdown +++ b/_blog-src/_posts/2015-05-19-rest-api.markdown @@ -4,6 +4,7 @@ title: "The JBoss apiman API Manager REST services API" date: 2015-05-19 11:00:00 author: len_dimaggio categories: rest api automation +newUrl: 2015-05-19-rest-api-redux --- In this, the third article in our series on apiman, JBoss' new open source API Management framework, we'll examine apiman’s API Manager REST services API. apiman’s Management UI utilizes this API in the implementation for all of its user-visible features, and you can also use the same API to automate tasks with apiman. diff --git a/_blog-src/_posts/2015-06-02-swagger-redux.markdown b/_blog-src/_posts/2015-06-02-swagger-redux.markdown new file mode 100644 index 000000000..8ce8193cf --- /dev/null +++ b/_blog-src/_posts/2015-06-02-swagger-redux.markdown @@ -0,0 +1,61 @@ +--- +layout: post +title: "We got the moves like swagger!" +date: 2015-06-02 09:04:45 +author: eric_wittmann +categories: api-manager swagger api ui +oldUrl: 2015-06-02-swagger +--- + +One of the weaknesses we've had in apiman until now is that API providers didn't have +any way to document how to consume their APIs. Well that has all changed with version +1.1.3.Final. Now you can upload a Swagger spec document for your API. If you do, +consumers will be able to browse your API documentation directly in the apiman UI. + +I think we can all agree that this is a welcome change and really improves the usability +of the system, particularly from the perspective of the client app developer (aka the +API consumer). + + + +## Adding an API Definition +As an API provider, the only thing you need to do is add an API definition to your +API. This is simple - just navigate to the new "Definition" tab in your API. +There you will be able to copy/paste or drag/drop a Swagger spec. Make sure you set the +definition type to Swagger (JSON), and don't forget to click Save! + +## What is a Swagger spec? +So maybe not everyone knows what Swagger is. Swagger is a way to formally describe a +RESTful API. A Swagger spec is a JSON document that describes everything +about your RESTful API, including (but not limited to): + +* API meta-data such as Name and Description +* Resource Paths and the Operations/Methods they support +* Input/Output types + +For more information I recommend navigating to the [Swagger Project](http://swagger.io/). + +## How does this help my consumers? +Once you've got a Swagger spec created and added to your API, your API +consumers will be able to browse live documentation right from the apiman UI. This +information will be available via a new "View API Definition" link available on +the consumer's "API Details" page (the same page that consumers are shown when +they have searched for an API). Here's an example: + +![API Details](/blog/images/2015-06-02/api-details.png) + +An API consumer can see that there is an API definition they can click on, which +will give them a ton of information about how to use the API. In the future, we +plan to allow consumers to do all sorts of interesting things with the Swagger spec. +For example, we can help consumers generate a client SDK in a variety of languages. +We can also allow them to simulate API calls right from the apiman UI - so they can +see what to expect. But for right now, we simply show live documentation about the +API as described by the Swagger spec definition: + + +![API Definition](/blog/images/2015-06-02/api-definition.png) + + +As always, thanks for making it to the end of my ramblings! + +/post diff --git a/_blog-src/_posts/2015-06-02-swagger.markdown b/_blog-src/_posts/2015-06-02-swagger.markdown index 00b1768dd..d09ff7d10 100644 --- a/_blog-src/_posts/2015-06-02-swagger.markdown +++ b/_blog-src/_posts/2015-06-02-swagger.markdown @@ -3,8 +3,10 @@ layout: post title: "We got the moves like swagger!" date: 2015-06-02 09:04:45 author: eric_wittmann -categories: api-manager swagger service ui +categories: api-manager swagger api ui +newUrl: 2015-06-02-swagger-redux --- + One of the weaknesses we've had in apiman until now is that service providers didn't have any way to document how to consume their services. Well that has all changed with version 1.1.3.Final. Now you can upload a Swagger spec document for your service. If you do, diff --git a/_blog-src/_posts/2015-06-04-dev-environment-redux.markdown b/_blog-src/_posts/2015-06-04-dev-environment-redux.markdown new file mode 100644 index 000000000..d07e73a46 --- /dev/null +++ b/_blog-src/_posts/2015-06-04-dev-environment-redux.markdown @@ -0,0 +1,220 @@ +--- +layout: post +title: "Setting up your apiman development environment" +date: 2015-06-04 09:04:45 +author: eric_wittmann +categories: eclipse development maven +oldUrl: 2015-06-04-dev-environment +--- + +For those of you who might be interested in hacking away at some core apiman code, +I thought it might be nice to create a reasonably comprehensive step-by-step +guide. For the most part everything is straightforward, but there are a copule +of tricks you can use to get up and running fast and to be able to easily +iterate on any changes you make. + +Read on if this sounds like something you want to do! + + + +## What will this post cover? +Here is a high level overview of the steps we'll take to getting a working +apiman development environment. First, here are my basic assumptions: + +* You are a java developer and have JDK7 or higher installed +* You are familiar with maven and have it installed +* You know git and have it installed +* You want to use the Eclipse IDE + +Assuming you meet all of the above requirements, you should have no trouble +with this guide! Here is what this post will cover: + +1. Getting the apiman source code +2. Downloading and running Eclipse +3. Configuring Eclipse for apiman development +4. Importing the apiman source code into Eclipse +5. Running Development versions of the apiman components + +## Getting the apiman source code +The first thing you (obviously) need to do is download the apiman project +source code. All of the code is in github, of course. You can find the +code here: + +[https://github.com/apiman/apiman](https://github.com/apiman/apiman) + +The 'apiman' github organization has a couple of additional repositories as +well. For example the quickstarts and plugins each have their own repos. +But let's stick with the core code for this post. + +If you want to follow best practice, you should "fork" the apiman repository +on github, then clone your forked copy. Once you have used the github UI +to fork the repository, you would do something like this: + +{% highlight text %} +git clone git@github.com:/apiman.git +{% endhighlight %} + +I also recommend adding the upstream github repository as another remote +so that you can easily pull in upstream changes: + +{% highlight text %} +git remote add upstream git@github.com:apiman/apiman.git +{% endhighlight %} + +## Downloading and running Eclipse +Alright - you've got the apiman code cloned on your local hard drive +somewhere. The next step is to download Eclipse (if you don't already +have it installed). This can be done here: + +[http://www.eclipse.org/downloads/](http://www.eclipse.org/downloads/) + +I like to download the "Eclipse IDE for Java EE Developers" version +because it comes with a lot of extra stuff I like to use. But you should +be fine with the basic version as well. I'm going to use the EE version +as I write this guide! + +Once you've completed the download, just unpack it and run Eclipse. + +![Fresh Eclipse](/blog/images/2015-06-04/eclipse-fresh.png) + +## Configuring Eclipse for apiman development +Great! You've got Eclipse running. Now let's make a minor change +to it specific to apiman development. Go ahead and import the apiman code +formatter specification. You can find this file in the apiman code +repository here: + +{% highlight text %} +apiman/tools/src/eclipse/apiman-eclipse-formatter.xml +{% endhighlight %} + +Import that file in the Eclipse Preferences dialog here: + +![Eclipse Preferences](/blog/images/2015-06-04/eclipse-formatter.png) + +## Importing the apiman source code into Eclipse +OK now we're ready to import the apiman source code into Eclipse. Because +apiman uses maven as its build system, and because Eclipse has maven support +built-in via m2e, this should be a snap. Simply go to *File->Import* and +choose *Maven/Existing Maven Projects*: + +![Import apiman](/blog/images/2015-06-04/import-apiman.png) + +![Import apiman Confirm](/blog/images/2015-06-04/import-apiman-2.png) + +Importing the projects into Eclipse may take some time, and Eclipse may +yell at you about unresolved m2e plugins and whatnot. Make sensible choices +(e.g. resolve later) and go about your life. Go get a cup of coffee, the +build will probably take a few minutes. + +It is possible you will run into a problem where the *apiman-manager-ui-hawtio* +project gets into a build loop. This can be corrected by disabling the +maven builder for that one project only. Do this by right-click on that +project and choosing properties: + +![Project Properties](/blog/images/2015-06-04/project-properties.png) + +Typically this will leave you with a bunch of annoying warnings in Eclipse, +most of which will be HTML Problems. I will leave it as an exercise to the +reader about how to disable those. + +IMPORTANT: you should have 0 java errors at this point! + +## Running Development versions of the apiman components +Everything should now be loaded into Eclipse. Now all you need is a quick +way to run everything. Of course you can *always* do a full rebuild via +maven and use the "install-all-wildfly8" profile: + +{% highlight text %} +cd ~/git/apiman +mvn clean install -Pinstall-all-wildfly8 +{% endhighlight %} + +That will result in a full apiman environment installed in WildFly 8. If you +use this approach you can run apiman here: + +{% highlight text %} +cd ~/git/apiman/tools/server-all/target/wildfly-8.2.0.Final +./bin/standalone.sh --debug +{% endhighlight %} + +Then you can connect a remote debugger to WildFly and debug apiman from Eclipse. + +But a quicker way to run the various apiman components exists. + +As you may or may not know, apiman consists of two components: + +* The API Manager (RESTful APIs + UI) +* The API Gateway + +You can run/test these pieces together or separately. Let's first explore +the API Manager. + +### Launching a Dev version of the API Manager REST APIs +This is actually really easy: + +1. Open up the java class *ManagerApiDevServer* +2. Debug As->Java Application + +Easy as that! It should fire up an instance of Jetty with the apiman API +Manager backend (RESTful APIs) deployed. You can test this by going +here: + +[http://localhost:7070/apiman/system/status](http://localhost:7070/apiman/system/status) + +Log in using username *admin* and password *admin*. Oh by the way, did I mention +that it runs on port 7070? That's important! + +### Using gulp to make UI changes +We use angularjs and typescript as the basis for the UI. In order to develop +UI code you'll need to use gulp. We have documented how to do this here: + +[https://github.com/apiman/apiman/blob/master/manager/ui/hawtio/README.md](https://github.com/apiman/apiman/blob/master/manager/ui/hawtio/README.md) + +Give that a quick read! When it asks you to configure your new copy of the +config.js file, it should look like this: + +{% highlight json %} +var APIMAN_CONFIG_DATA = { + "apiman" : { + "version" : "1.1.0-SNAPSHOT", + "builtOn" : "2015-01-01", + "logoutUrl" : "logout" + }, + "user" : { + "username" : "admin" + }, + "ui" : { + "header" : true + }, + "api" : { + "endpoint" : "http://localhost:7070/apiman", + "auth" : { + "type" : "basic", + "basic" : { + "username" : "admin", + "password" : "admin" + } + } + } +}; +{% endhighlight %} + +If you get it all set up properly you should be able to point your browser here: + +[http://localhost:2772/api-manager/dash](http://localhost:2772/api-manager/dash) + +Now whenever you make changes to any of the apiman angularjs code, the browser +will automatically refresh and show you the changes! + +### Launching a dev version of the API Gateway +This one is easy as well. Just open up the *GatewayDevServer* java class +and debug it as an application (just like the API Manager above!)... + + +## Wrapup +Whew! That took longer than I thought. Please let me know if you run into +any snags. There are probably lots of improvements you could explore, such as +using JRebel to never have to restart the API Manager or API Gateway java +processes again. + +/post diff --git a/_blog-src/_posts/2015-06-04-dev-environment.markdown b/_blog-src/_posts/2015-06-04-dev-environment.markdown index 200faf0a2..84c46a1f1 100644 --- a/_blog-src/_posts/2015-06-04-dev-environment.markdown +++ b/_blog-src/_posts/2015-06-04-dev-environment.markdown @@ -4,7 +4,9 @@ title: "Setting up your apiman development environment" date: 2015-06-04 09:04:45 author: eric_wittmann categories: eclipse development maven +newUrl: 2015-06-04-dev-environment-redux --- + For those of you who might be interested in hacking away at some core apiman code, I thought it might be nice to create a reasonably comprehensive step-by-step guide. For the most part everything is straightforward, but there are a copule diff --git a/_blog-src/_posts/2015-06-11-basic-auth-redux.markdown b/_blog-src/_posts/2015-06-11-basic-auth-redux.markdown new file mode 100644 index 000000000..7a086116f --- /dev/null +++ b/_blog-src/_posts/2015-06-11-basic-auth-redux.markdown @@ -0,0 +1,155 @@ +--- +layout: post +title: "Adding a BASIC Authentication Policy to a Managed API in JBoss apiman" +date: 2015-06-11 11:00:00 +author: len_dimaggio +categories: authentication policy +oldUrl: 2015-06-11-basic-auth-redux +--- + +![apiman logo](/blog/images/2015-06-11/1-apiman_logo.png) + +In this, the fourth article in the series on apiman, JBoss' new API Management framework, we'll examine how apiman enables you to not just manage APIs, but implement a layer of security to the APIs by adding an authentication requirement when client apps access a managed API. + + + +## Securing Client App Access to your Managed APIs + + As we've seen in the previous articles in this series, apiman enables you to govern the usage of the APIs that it manages by defining policies in the Managament UI that are then applied at runtime by the API Gateway. The apiman API Gateway applies the policy rules that you define to requests that it proxies to the managed API: + +![apiman logo](/blog/images/2015-06-11/apiman-2.png) + +The OOTB policies that are packaged with apiman enable you to apply a variety of types of controls, including rate limiting (where access to an API is assigned a usage threshold) and black/whitelisting by IP address (where the client app's IP address governs their access to the API). + + However, managing an API with apiman does not automatically make that API secure. Happily, however, apiman provides a policy that enables you to easily set up authentication to control access to your managed API. (Note that this policy governs the client apps' authenticated access to the managed API, and not establishing a secure connection where apiman authenticates the back-end APIs. In other words, in this article, we're interested in adding authentication between the blue and pink boxes in the above diagram.) + +## Adding a BASIC Authentication Policy to a Managed API + + apiman is packaged with multiple pre-configured policies: + +* Authorization - Access to APIs' resources is controlled by user roles. +* BASIC Authentication - A username/password is required to access an API. +* Ignored Resources - Paths to APIs' resources that will not be accessible. Requests to these API resource paths return a 404 (not found) error. +* IP Blacklist - Client apps with specific IP address will be blocked from accessing an API. +* IP Whitelist - And, client apps with specific IP address will not be blocked from accessing an API. +* Rate Limiting - Access to an API is limited by the number of requests in a defined time period. We demonstrated an example of a rate limiting policy in the first article in this series. + + We're interested in the BASIC Authentication Policy. Let's take a closer look. The dialog to add a BASIC authentication policy to an API looks like this: + +![apiman logo](/blog/images/2015-06-11/apiman-3.png) + +In creating the BASIC policy, we define an Authentication Realm (think of this as an area to be protected, within which usernames and passwords exist) and an optional HTTP header. The optional HTTP header is used to optionally pass the user's principal to the back-end API through an HTTP header. This is useful if the back-end system needs to know the username of the user calling it (e.g. to do user-specific operation). The "Transport security required" checkbox, if enabled, will cause the policy to fail if a client app tries to connect to the API over http. The Policy will only accept credentials over https. + + We'll keep the Identity Source simple and select "Static Identities" and then define a user. Note that while this static approach is fine for testing purposes, you will want use one of the other Identity Source options (JBDS or LDAP) for a production environment as they can better handle a large number of users. + + ![apiman logo](/blog/images/2015-06-11/apiman-4.png) + +It's important to remember that, in BASIC authentication, one of the factors that makes this, well, basic in nature, is that the username/password that you define are encoded (this is unencrypted base64 encoded text) when they are sent to the server. Since the text is not encrypted, it's at risk of being copied and then used in an attack. For this reason, it's safer to select the transport security option to configure SSL encryption. + + To illustrate, here's Java code that can encode and then decode the username:password string: + +{% highlight bash %} + Base64.Encoder encoder = Base64.getEncoder(); + String normalString = "user1" + ":" + "password1"; + String encodedString = encoder.encodeToString(normalString.getBytes(StandardCharsets.UTF_8)); + System.out.println ("The encoded string is: " + encodedString); + + Decoder decoder = Base64.getDecoder(); + byte[] unencodedStringArray = decoder.decode(encodedString); + String unencodedString = new String (unencodedStringArray); + System.out.println ("The unencoded string is: " + unencodedString); + + The encoded string is: dXNlcjE6cGFzc3dvcmQx + The unencoded string is: user1:password1 +{% endhighlight %} + + So - unlike encrypted strings, your encoded username and password strings are not secure! + + ## When a Request is made to the API + +It's interesting to see step-by-step what happens when a request is made to the API and the BASIC authentication policy is applied. Let's take a look at the request and the responses. I used the "HttpFox" http analyzer (https://addons.mozilla.org/en-us/firefox/addon/httpfox/) to "listen in" on the requests sent to the server and the responses sent back. + + Here's the first request made to the API, notice that a username/password is not included. + +{% highlight bash %} + (Request-Line) GET /apiman-gateway/apiProducerOrg/echossl/1.0?apikey=6f8784cd-5754-47b0-9b8b-b2eb8c5b190f HTTP/1.1 + Host localhost:8443 + User-Agent Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Firefox/24.0 + Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 + Accept-Language en-US,en;q=0.5 + Accept-Encoding gzip, deflate + Cookie __utma=111872281.1348865079.1409020839.1411395889.1419258109.7; __utmz=111872281.1409020839.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); s_fid=72CCAD206D09146C-233B60F47DBEA290 + Connection keep-alive +{% endhighlight %} + +The response, as we expected, shows that the request has triggered an authentication failure. This is due to the authentication requirement that we defined and is being applied by the API Gateway. Note the 401 error code and the reference to BASIC authentication: + +{% highlight bash %} + (Status-Line) HTTP/1.1 401 Unauthorized + X-Powered-By Undertow/1 + Server WildFly/8 + X-Policy-Failure-Type Authentication + Date Wed, 03 Jun 2015 13:43:26 GMT + Connection keep-alive + WWW-Authenticate BASIC realm="myRealm" + X-Policy-Failure-Code 10004 + Content-Type application/json + Content-Length 165 + X-Policy-Failure-Message BASIC authentication failed. +{% endhighlight %} + +The browser then automatically pops up a dialog for us to enter the username and password: + +![apiman logo](/blog/images/2015-06-11/apiman-5.png) + + + A request is then sent that includes the username and password encoded into a string. In this request, the encoded (but not encrypted) username and password are included: + +{% highlight bash %} + (Request-Line) GET /apiman-gateway/apiProducerOrg/echossl/1.0?apikey=6f8784cd-5754-47b0-9b8b-b2eb8c5b190f HTTP/1.1 + Host localhost:8443 + User-Agent Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Firefox/24.0 + Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 + Accept-Language en-US,en;q=0.5 + Accept-Encoding gzip, deflate + Cookie __utma=111872281.1348865079.1409020839.1411395889.1419258109.7; __utmz=111872281.1409020839.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); s_fid=72CCAD206D09146C-233B60F47DBEA290 + Connection keep-alive + Authorization Basic dXNlcjE6cGFzc3dvcmQx +{% endhighlight %} + +And, then we get the successful return code of 200 in a response: + +{% highlight bash %} + (Status-Line) HTTP/1.1 200 OK + Connection keep-alive + X-Powered-By Undertow/1 + Server WildFly/8 + Content-Length 755 + Content-Type application/json + Date Wed, 03 Jun 2015 13:43:34 GMT + {% endhighlight %} + +## In Conclusion + + Just because an API is managed doesn't automatically make it secure. JBoss apiman provides you with multiple options to add an authentication requirement when client apps access your managed API. + +## Author's Acknowledgements + + As always, the author would like to acknowledge Eric Wittmann and the apiman team for their review comments and suggestions on writing this post, and for adding new features to apiman! + +## Links + +apiman + +* http://www.apiman.io + +Previous articles in this series: + +* http://java.dzone.com/articles/impatient-new-users +* http://java.dzone.com/articles/customizing-jboss-apiman +* http://java.dzone.com/articles/jboss-apiman-api-manager-rest + +HTTP Authentication: Basic and Digest Access Authentication + +* http://tools.ietf.org/html/rfc2617 + diff --git a/_blog-src/_posts/2015-06-11-basic-auth.markdown b/_blog-src/_posts/2015-06-11-basic-auth.markdown index 73fb8de12..94cb4de6a 100644 --- a/_blog-src/_posts/2015-06-11-basic-auth.markdown +++ b/_blog-src/_posts/2015-06-11-basic-auth.markdown @@ -4,6 +4,7 @@ title: "Adding a BASIC Authentication Policy to a Managed Service in JBoss apim date: 2015-06-11 11:00:00 author: len_dimaggio categories: authentication policy +newUrl: 2015-06-11-basic-auth --- ![apiman logo](/blog/images/2015-06-11/1-apiman_logo.png) diff --git a/_blog-src/_posts/2015-07-06-metrics-redux.markdown b/_blog-src/_posts/2015-07-06-metrics-redux.markdown new file mode 100644 index 000000000..530e75aa8 --- /dev/null +++ b/_blog-src/_posts/2015-07-06-metrics-redux.markdown @@ -0,0 +1,132 @@ +--- +layout: post +title: "At long last, Metrics R Us!" +date: 2015-07-06 15:10:22 +author: eric_wittmann +categories: api-manager api ui metrics +oldUrl: 2015-07-06-metrics +--- + +A core feature of any good API Management solution is the recording of and reporting on +interesting metrics related to API requests. Because apiman acts as a central Gateway +for all managed API traffic, it is the perfect location to record information about each +and every request. This allows it to report on interesting data it has recorded, related +to response times, successful vs. failed requests, total number of requests broken down +by time, consumer id, or plan used. As you can imagine, this is extremely valuable +information and it is a bit embarrassing that we haven't offered this functionality until +now! + +But that gap is finally filled with version 1.1.4.Final. + + + +## Overview +First let me give you just a high level overview of what this is all about. Every time +the API Gateway gets a request from an API client, it will add a record in the metrics +system with a bunch of interesting fields. These include but are not limited to: + +* Request start and end times +* API start and end times (i.e. just the part of the request taken up by the back end service) +* Resource path +* Response type (success, failure, error) +* API info (org id, id, version) +* Client app info (org id, id, version) + +All of this information is recorded in the metrics storage system so that later on it +can be analyzed/mined for interesting trends. + +In the API Manager, we extract interesting reports from the recorded metrics data and +display it as graphs in the UI (as well as provide the data via a set of metrics +related REST endpoints in the API Manager's own API). + +## How do we store metrics? +Out of the box, apiman stores the metrics information into an elasticsearch index. This +elasticsearch instance is provided as part of the apiman distribution and is enabled and +running by default. If you wish to use a different elasticsearch instance that's of +course no problem - all it requires is some tweaking of settings in the apiman.properties +file. I recommend having a look at the [Installation Guide](http://www.apiman.io/latest/installation-guide.html) +for more details. + +The intention is to support various metrics storage systems, not just elasticsearch. +For example, we have InfluxDB and Hawkular implementations in progres. You can even +implement your own! Custom metrics systems is likely a separate blog post, but note +that *storing* metrics data into an alternate system is easy - simply implement the +*IMetrics* interface: + +{% highlight java %} +package io.apiman.gateway.engine; + +public interface IMetrics { + + /** + * Records the metrics for a single request. Most implementations will likely + * asynchronously process this information. + */ + public void record(RequestMetric metric); + + /** + * Provides the component registry (before any call to {@link #record(RequestMetric)}) + * is made. Metrics can then access HTTP client components, etc. + */ + public void setComponentRegistry(IComponentRegistry registry); +} +{% endhighlight %} + +A little bit of configuration foo in the apiman.properties is all it takes to switch +from elasticsearch to your custom provider. + + +## Metrics data from the API Manager's REST API +There is no way to extract arbitrary metrics information from the metrics source unless +you hit the metrics storage directly. For example, you could use Kibana to directly +view the apiman metrics information stored in elasticsearch. In the future we will +be exploring ways to integrate the data visualization tools that come with each of the +providers we support (elasticsearch, hawkular, influxcb, etc). However, we do provide +a set of REST endpoints you can use to extract common metrics. These REST endpoints are +available as a part of the standard API Manager's REST API. + +Please refer to the [API documentation](http://www.apiman.io/latest/api-manager-restdocs.html) +for the latest information, but at the time of this blog post the available metrics +endpoints are: + +* /organizations//apis//versions//metrics/usage +* /organizations//apis//versions//metrics/appUsage +* /organizations//apis//versions//metrics/planUsage +* /organizations//apis//versions//metrics/responseStats +* /organizations//apis//versions//metrics/summaryResponseStats +* /organizations//apis//versions//metrics/planResponseStats +* /organizations//apis//versions//metrics/appResponseStats + +The 'usage' endpoints return information about the number of requests made. The +'responseStats' endpoints are similar, but are broken down by response type (successful +vs. failed vs. error responses). All endpoints require a time range (from and to). The +*/usage* and */responseStats* endpoints also require a time interval, because they both +return a histogram/time series dataset. + +Sensible limits are enforced on all these endpoints to discourage abuse. For example, +don't ask for a per-minute granularity time series dataset over a ten year data range. +The system won't like that one bit. + + +## Viewing metrics info in the UI +The metrics information provided by the API is also available directly in the API Manager +UI. For any published API, simply navigate to the *Metrics* tab for that API +(in the provider section of the UI). The UI should be pretty easy to use - simply pick +a type of metric you want to see and a pre-configured time period! Here is what the +usage metrics might look like for a typical API: + +![Usage Metrics](/blog/images/2015-07-06/usage-metrics.png) + +And here is what you might expect to find for typical response type metrics: + +![Response Type Metrics](/blog/images/2015-07-06/response-type-metrics.png) + + +## Conclusion +As you can see, this is highly valuable information to have. We only have a couple of +different categories of metrics exposed via the API and UI right now - so this is +your opportunity to come tell us what you'd like to see! Join the apiman metrics +conversation on our [mailing list](https://lists.jboss.org/mailman/listinfo/apiman-user) +or [IRC channel](http://www.apiman.io/latest/chat.html). + +/post diff --git a/_blog-src/_posts/2015-07-06-metrics.markdown b/_blog-src/_posts/2015-07-06-metrics.markdown index c9a2a1df0..cd4b8eb44 100644 --- a/_blog-src/_posts/2015-07-06-metrics.markdown +++ b/_blog-src/_posts/2015-07-06-metrics.markdown @@ -4,7 +4,9 @@ title: "At long last, Metrics R Us!" date: 2015-07-06 15:10:22 author: eric_wittmann categories: api-manager service ui metrics +newUrl: 2015-07-06-metrics-redux --- + A core feature of any good API Management solution is the recording of and reporting on interesting metrics related to API requests. Because apiman acts as a central Gateway for all managed API traffic, it is the perfect location to record information about each diff --git a/_blog-src/_posts/2015-07-07-fuse-apis-redux.markdown b/_blog-src/_posts/2015-07-07-fuse-apis-redux.markdown new file mode 100644 index 000000000..7edd2ef82 --- /dev/null +++ b/_blog-src/_posts/2015-07-07-fuse-apis-redux.markdown @@ -0,0 +1,172 @@ +--- +layout: post +title: "Manage Fuse APIs with apiman" +date: 2015-07-07 15:15:15 +author: sbunciak +categories: api management jboss fuse +oldUrl: 2015-07-07-fuse-apis +--- + +This article aims to provide a short guide on how to get API Management capabilities provided by apiman to work with JBoss Fuse, a lightweight, flexible, integration platform that is based on [Apache Camel](http://camel.apache.org), an implementation of many of the most commonly used enterprise integration patterns (EIP). + + + +Creating API provider in JBoss Fuse +==================================== + +The following few steps should quickly get you started with deploying applications into JBoss Fuse. For demonstration purposes I'm using a sample REST application (quickstart) shipped along with Fuse installation. For more information about developing applications for JBoss Fuse inspect the [developer materials](http://www.jboss.org/products/fuse/developer-materials/#!project=fuse) and other [resources](http://www.jboss.org/products/fuse/resources/) at jboss.org. + +### Installation +To obtain a distribution of JBoss Fuse please visit the JBoss Fuse [download page](http://www.jboss.org/products/fuse/download/). +Installation of JBoss Fuse is very simple, as the only thing you need to do is to unzip the distribution, e.g. + +{% highlight sh %} +unzip jboss-fuse-full-6.2.0.redhat-133.zip +{% endhighlight %} + +You might also want to enable the default admin user by uncommenting the last line in `/etc/users.properties`. Without a user configured you won't be able to log into Fuse management console. + +### Server startup + +To start Fuse simply execute the following command from `/bin`: + +{% highlight sh %} +./fuse +{% endhighlight %} + +Once JBoss Fuse is loaded proceed by creating a new Fuse Fabric instance. To do that execute `fabric:create` command from Fuse CLI: + +{% highlight sh %} +JBossFuse:karaf@root> fabric:create +{% endhighlight %} + +After Fuse Fabric is up and running, log into Hawt.io management console, it should be by default available at [http://localhost:8181](http://localhost:8181). +In Fabric perspective, under Containers tabs click on the _Create_ button to open the _Create New Container form_. + +![List of Fabric containers](/blog/images/2015-07-07/fabric.png) + +On the _Create New Container_ page fill in the name you wish to use for your container (e.g. my-rest-container) and be sure to select the 'rest' profile for it. This will ensure that Fabric pickups the REST Quickstart and deploys it to this container. Finish the operation by hitting the _Create and start container_ button. + +![Create Fabric Container](/blog/images/2015-07-07/container.png) + +The container should start automatically right after it has been created and the REST endpoint should become available. If not, select the appropriate container and hit Start. +You can inspect all the APIs deployed to your Fuse Fabric instance by clicking on _APIs_ section under the _APIs_ tab. +Note the _Location_ field - that's the **base url** the for endpoint implementation. We will use it later in the apiman manager. + +![APIs deployed to Fuse Fabric](/blog/images/2015-07-07/services.png) + +There is a default user preconfigured so you can verify if the application was successfully deployed. It's available at `/customerservice/customers/123` (e.g. [http://localhost:8182/cxf/crm/customerservice/customers/123](http://localhost:8182/cxf/crm/customerservice/customers/123)) + +{% highlight xml %} +[sbunciak@sbunciak ~]$ http http://localhost:8182/cxf/crm/customerservice/customers/123 +HTTP/1.1 200 OK +Content-Type: application/xml +Date: Tue, 07 Jul 2015 22:17:13 GMT +Server: Jetty(8.1.17.v20150415) +Transfer-Encoding: chunked + + + + 123 + John + +{% endhighlight %} + +Configure apiman to manage Fuse endpoint +======================================== + +To install the latest version of apiman follow this [guide](http://www.apiman.io/latest/download.html). The installation process is again very simple, all you need to do is to extract the apiman overlay zip on top of [Wildly 8](http://www.wildfly.org/) server. + +After completing the installation, start apiman by executing the following command from `/bin` folder: + +{% highlight sh %} +./standalone.sh -c standalone-apiman.xml +{% endhighlight %} + +### Quick public API setup + +For demonstration purposes I'll be creating a Public API, however in real life you might want to configure different plans, various contracts, etc. +Please consult the apiman [user guide](http://www.apiman.io/latest/user-guide.html) for more details. + +In order to manage APIs in apiman you need to create a new Organization to which your APIs will belong. +You can do that easily in apiman manager, typically available at: [http://localhost:8080/apimanui](http://localhost:8080/apimanui). + +Once logged into the apiman manager, locate the Organizations sections on the initial page, select _Create a New Organization_ link, provide a name and hit _Create Organization_ button. This will take you to organization details page where you can create a new API by clicking on _New API_ button under _APIs_ tab: + +![Image: Create API](/blog/images/2015-07-07/API.png) + +You will be asked to provide a name and a version for this API. Once the API is successfully created there are few things remaining before you can publish and start using it. +First, you need to provide an implementation base url on the _Implementation_ tab. Use the base URL of the REST Quickstart and save your changes: + +![Image: Provide Endpoint Implementation](/blog/images/2015-07-07/implementation.png) + +Second, you may want to apply some policies to this Public API. To do that, go to the Policies tab and configure a policy of your choice. +I used the Rate Limiting policy to limit usage of this API to 5 per minute: + +![Image: Assign policy](/blog/images/2015-07-07/policy.png) + +Now you are all set to make the API public by checking _Make this API public_ under _Plans_ tab, saving the changes and clicking the _Publish_ button (which should be now enabled). + +![Image: Publish API](/blog/images/2015-07-07/publish.png) + +After you have published the API, have a look at the _Endpoint_ tab to look up the URL to be used to invoke this public API: + +![Image: Managed API Endpoint](/blog/images/2015-07-07/endpoint.png) + +Testing your setup +================== + +Depending on which policy you assinged to the Public API you might experience different behavior. However, if you followed the tutorial and assigned the Rate Limiting policy after reaching the maximum number of allowed requests you will get an output similar to: + +* First request should succeed: + +{% highlight xml %} +[sbunciak@sbunciak ~]$ http https://localhost:8443/apiman-gateway/CustomerOrganization/CrmRestApi/1.0/customerservice/customers/123 --verify=no +HTTP/1.1 200 OK +Connection: keep-alive +Content-Type: application/xml +Date: Tue, 07 Jul 2015 21:01:02 GMT +Server: Jetty(8.1.17.v20150415) +Transfer-Encoding: chunked +X-Powered-By: Undertow/1 +X-RateLimit-Limit: 5 +X-RateLimit-Remaining: 4 +X-RateLimit-Reset: 57 + + + + 123 + John + +{% endhighlight %} + +* Executing 5 consecutive requests should fail with `HTTP 429 Too Many Requests`: + +{% highlight sh %} +[sbunciak@sbunciak ~]$ http https://localhost:8443/apiman-gateway/CustomerOrganization/CrmRestApi/1.0/customerservice/customers/123 --verify=no +HTTP/1.1 429 Too Many Requests +Connection: keep-alive +Content-Length: 176 +Content-Type: application/json +Date: Tue, 07 Jul 2015 21:00:51 GMT +Server: WildFly/8 +X-Policy-Failure-Code: 10005 +X-Policy-Failure-Message: Rate limit exceeded. +X-Policy-Failure-Type: Other +X-Powered-By: Undertow/1 +X-RateLimit-Limit: 5 +X-RateLimit-Remaining: 0 +X-RateLimit-Reset: 8 + +{ + "failureCode": 10005, + "headers": { + "X-RateLimit-Limit": "5", + "X-RateLimit-Remaining": "0", + "X-RateLimit-Reset": "8" + }, + "message": "Rate limit exceeded.", + "responseCode": 429, + "type": "Other" +} +{% endhighlight %} diff --git a/_blog-src/_posts/2015-07-07-fuse-apis.markdown b/_blog-src/_posts/2015-07-07-fuse-apis.markdown index d9355fecf..ef2ea5b67 100644 --- a/_blog-src/_posts/2015-07-07-fuse-apis.markdown +++ b/_blog-src/_posts/2015-07-07-fuse-apis.markdown @@ -4,6 +4,7 @@ title: "Manage Fuse APIs with apiman" date: 2015-07-07 15:15:15 author: sbunciak categories: api management jboss fuse +newUrl: 2015-07-07-fuse-apis-redux --- This article aims to provide a short guide on how to get API Management capabilities provided by apiman to work with JBoss Fuse, a lightweight, flexible, integration platform that is based on [Apache Camel](http://camel.apache.org), an implementation of many of the most commonly used enterprise integration patterns (EIP). diff --git a/_blog-src/_posts/2015-07-24-plugin-components-redux.markdown b/_blog-src/_posts/2015-07-24-plugin-components-redux.markdown new file mode 100644 index 000000000..fb38b7f90 --- /dev/null +++ b/_blog-src/_posts/2015-07-24-plugin-components-redux.markdown @@ -0,0 +1,243 @@ +--- +layout: post +title: "Plugins - Not Just For Policies Anymore" +date: 2015-07-24 14:10:10 +author: eric_wittmann +categories: api-manager api-gateway plugins development maven +oldUrl: 2015-07-24-plugin-components +--- + +As you may know, apiman has long supported custom policies provided by users. If you +aren't familiar with apiman plugins, you can find more about them by [clicking here](http://www.apiman.io/blog/plugins/policies/development/maven/2015/03/06/custom-policies.html). + +As of version 1.1.5.Final, plugins are now even more useful. You can provide custom +implementations of various core apiman system components via plugins. This allows users +to customize apiman easily, without any changes to the classpath and without rebuilding +the core apiman application. + +In this blog post I'll explain how it works. + + + +## Review: What is a plugin? +First, here are some good resources you can use to learn more about apiman plugins: + +* [Customizing JBoss apiman Through Policy Plugins](http://www.apiman.io/blog/plugins/policies/development/maven/2015/03/06/custom-policies.html) +* [apiman Developer Guide: Plugins](http://www.apiman.io/latest/developer-guide.html#_plugins) + +No patience to read those links? That's OK - I'll give you a quick breakdown. + +An apiman plugin is basically a WAR file with one additional required file. The additional +file is `META-INF/apiman/plugin.json` and it contains some meta-data about the plugin. An +example of a plugin.json file (from the JSONP policy plugin): + +{% highlight json %} +{ + "frameworkVersion" : 1.0, + "name" : "JSONP Policy Plugin", + "description" : "This plugin turns an endpoint into a JSONP compatible endpoint.", + "version" : "1.1.5.Final" +} +{% endhighlight %} + +We chose WAR as the plugin format because it allows all of the file types we need, it +is a well-known structure, and it's easy to create (e.g. via maven). + +When contributing a custom apiman component via a plugin, all you need is the `plugin.json` +file and the java class file(s) that implement the appropriate component interface. Of +course, because a plugin is a WAR, you can also include any library dependencies your +component might need. + + +## What are these components are you talking about? +apiman is made up of a number of components that work together to accomplish the goal of +API Management. There are two primary pieces of the apiman story: + +* API Manager +* API Gateway + +Each of these consists of its own components. For example, the API Manager is made up of +the following (not necessarily an exhaustive list): + +* Storage Component +* Query Component +* IDM Component +* Metrics Accessor Component (consumes metrics data) + +On the other hand, the API Gateway consists of a separate set of components, such as: + +* Configuration Registry +* Rate Limiting Component +* Shared State Component +* Metrics Component (produces metrics data) + +By default, the apiman quickstart uses default values for all of these, resulting in +a stable, working system with the following characteristics: + +* Stores API Manager data in a JDBC database +* Records and queries metrics data via Elasticsearch +* Stores Gateway configuration information in Infinispan +* Uses infinispan to share rate limiting state across gateway nodes + +There are alternative configurations of apiman that you can use without needing to +resort to plugins. For example, we provide Elasticsearch implementations of many of +the components mentioned above. So you could easily switch from Infinispan to ES in +the Gateway, if you wanted. However, if you wish to provide a custom implementation +of something, plugins are now the way to go! + + +## Example Scenario +There is a lot you can do now that we support plugin components. But it's probably +easiest to explain and understand if we take a simple example scenario. + +### Use mongodb to store Gateway configuration information +If you download the apiman quickstart, the default configuration is to use the built +in WildFly 8 infinispan subsystem to store the API Gateway configuration info. This +includes all APIs published to the Gateway, and all client apps registered with +it as well. Perhaps you would rather that data be stored in mongodb? Since we don't +have a mongodb implementation of the Gateway Registry, you'll need to implement it +yourself and bundle it up into a plugin! + +### Create a apiman-gateway-mongodb plugin +I won't go through the entire process of creating an apiman plugin here, since it is +already well documented (and linked above). You'll need a WAR maven project with a +`plugin.json` file in the right place, which might look something like this: + +{% highlight json %} +{ + "frameworkVersion" : 1.0, + "name" : "mongodb plugin", + "description" : "This plugin provides a mongodb implementation of the Gateway registry.", + "version" : "1.0" +} +{% endhighlight %} + +You will also need an implementation of the Gateway's `io.apiman.gateway.engine.IRegistry` +interface. Let's call it `MongoDbRegistry.java`: + +{% highlight java %} +package org.example.apiman.gateway; + +import io.apiman.gateway.engine.async.IAsyncResultHandler; +import io.apiman.gateway.engine.beans.ClientApp; +import io.apiman.gateway.engine.beans.Api; +import io.apiman.gateway.engine.beans.ApiContract; +import io.apiman.gateway.engine.beans.ApiRequest; + +import java.util.Map; + +/** + * An implementation of the {@link IRegistry} interface using mongodb. + */ +public class MongoDbRegistry implements IRegistry { + + /** + * Constructor. + * @param config + */ + public MongoDbRegistry(Map config) { + super(config); + } + + /** + * @see io.apiman.gateway.engine.IRegistry#getContract(io.apiman.gateway.engine.beans.ApiRequest, io.apiman.gateway.engine.async.IAsyncResultHandler) + */ + @Override + public void getContract(ApiRequest request, IAsyncResultHandler handler) { + // TODO Auto-generated method stub + } + + /** + * @see io.apiman.gateway.engine.IRegistry#publishApi(io.apiman.gateway.engine.beans.Api, io.apiman.gateway.engine.async.IAsyncResultHandler) + */ + @Override + public void publishApi(Api service, IAsyncResultHandler handler) { + // TODO Auto-generated method stub + } + + /** + * @see io.apiman.gateway.engine.IRegistry#retireApi(io.apiman.gateway.engine.beans.Api, io.apiman.gateway.engine.async.IAsyncResultHandler) + */ + @Override + public void retireApi(Api service, IAsyncResultHandler handler) { + // TODO Auto-generated method stub + } + + /** + * @see io.apiman.gateway.engine.IRegistry#registerClientApp(io.apiman.gateway.engine.beans.ClientApp, io.apiman.gateway.engine.async.IAsyncResultHandler) + */ + @Override + public void registerClientApp(ClientApp application, IAsyncResultHandler handler) { + // TODO Auto-generated method stub + } + + /** + * @see io.apiman.gateway.engine.IRegistry#unregisterClientApp(io.apiman.gateway.engine.beans.ClientApp, io.apiman.gateway.engine.async.IAsyncResultHandler) + */ + @Override + public void unregisterClientApp(ClientApp application, IAsyncResultHandler handler) { + // TODO Auto-generated method stub + } + + /** + * @see io.apiman.gateway.engine.IRegistry#getApi(java.lang.String, java.lang.String, java.lang.String, io.apiman.gateway.engine.async.IAsyncResultHandler) + */ + @Override + public void getApi(String organizationId, String apiId, String apiVersion, + IAsyncResultHandler handler) { + // TODO Auto-generated method stub + } +} +{% endhighlight %} + +Obviously you will want to include any mongodb client libraries you need, and then +implement the actual functionality of the class. I leave that as an exercise for the +reader. Note that most of the Gateway components have asynchronous APIs. If possible +you should attempt to use asynchronous techniques when providing implementations. + +### Switching to your custom implementation in apiman.properties +Now you've got a component you want to use, and it's all nicely wrapped up in a shiny +new plugin. Your next step is to actually use it! Using a custom component is as +simple as referencing it in the `apiman.properties` file. You'll need to remove +this line first: + +{% highlight text %} +apiman-gateway.registry=io.apiman.gateway.engine.ispn.InfinispanRegistry +{% endhighlight %} + +and then add something like this: + +{% highlight text %} +apiman-gateway.registry=plugin:GROUP_ID:ARTIFACT_ID:VERSION/org.example.apiman.gateway.MongoDbRegistry +{% endhighlight %} + +The format of the value of `apiman-gateway.registry` is very important - when +using a plugin you must specify the maven information of your plugin so that +apiman can locate and download it. See the apiman documentation for additional +details about how plugins are loaded. + +Note that you can also provide configuration parameters to your component. That +will obviously be helpful since it will probably need connection details. So +really your configuration might look something like this: + +{% highlight text %} +apiman-gateway.registry=plugin:GROUP_ID:ARTIFACT_ID:VERSION/org.example.apiman.gateway.MongoDbRegistry +apiman-gateway.registry.mongo.host=localhost +apiman-gateway.registry.mongo.port=27017 +apiman-gateway.registry.mongo.username=sa +apiman-gateway.registry.mongo.password=sa123! +apiman-gateway.registry.mongo.database=apiman +{% endhighlight %} + +These configuration options will be passed to your component in its constructor if +your class has a `Map` constructor. + + +## Conclusion +This is a powerful new feature for extending and customizing apiman to better suit +your needs. Of course we will want to continue offering the most popular component +implementations as a core part of apiman. However there will always be many more +options than we can easily implement and support. For this reason we wanted to +provide an easy way for users (and the apiman community at large) to contribute. + +/post diff --git a/_blog-src/_posts/2015-07-24-plugin-components.markdown b/_blog-src/_posts/2015-07-24-plugin-components.markdown index 10aeb4aac..62ccaf964 100644 --- a/_blog-src/_posts/2015-07-24-plugin-components.markdown +++ b/_blog-src/_posts/2015-07-24-plugin-components.markdown @@ -4,7 +4,9 @@ title: "Plugins - Not Just For Policies Anymore" date: 2015-07-24 14:10:10 author: eric_wittmann categories: api-manager api-gateway plugins development maven +newUrl: 2015-07-24-plugin-components-redux --- + As you may know, apiman has long supported custom policies provided by users. If you aren't familiar with apiman plugins, you can find more about them by [clicking here](http://www.apiman.io/blog/plugins/policies/development/maven/2015/03/06/custom-policies.html). @@ -85,7 +87,7 @@ of something, plugins are now the way to go! ## Example Scenario -There is a lot you can do now taht we support plugin components. But it's probably +There is a lot you can do now that we support plugin components. But it's probably easiest to explain and understand if we take a simple example scenario. ### Use mongodb to store Gateway configuration information diff --git a/_blog-src/_posts/2015-08-03-policy-endpoint-security-redux.markdown b/_blog-src/_posts/2015-08-03-policy-endpoint-security-redux.markdown new file mode 100644 index 000000000..f0a178f4e --- /dev/null +++ b/_blog-src/_posts/2015-08-03-policy-endpoint-security-redux.markdown @@ -0,0 +1,71 @@ +--- +layout: post +title: "apiman Policy and Endpoint Security" +date: 2015-08-03 11:00:00 +author: len_dimaggio +categories: security +oldUrl: 2015-08-03-policy-endpoint-security +--- + +In this, the fifth article in the series on apiman, JBoss’ new API Management framework, we’ll examine how apiman enables you to provide security for your managed APIs at the policy level, and and at the endpoint level for its managed and unmanaged endpoints. + + + +##Unintentionally Insecure? + +If you read the first article in this series closely (https://dzone.com/articles/impatient-new-users) you might have noticed that in the course of creating an API whose endpoint was managed by the apiman API Gateway, we also inadvertently left that API in a very insecure state as unauthorized client apps could bypass the gateway and access the API directly. We discussed how to configure authentication in a policy for the managed API endpoint in the most recent post in this series (https://dzone.com/articles/adding-basic-authentication). This authentication policy provides username/password security for clients as they access the managed API through the API Gateway, but it does not protect the API from unauthorized access attempts that bypass the Gateway completely. To make the API secure from unauthorized client apps, endpoint level security should also be configured. + +In this article, we’ll examine both apiman policy level and endpoint level security, how they compare, and how they differ. + +##Complementary Types of Security Provided by apiman + +The best way to start our discussion of the different, but complementary types of security that we’ll examine in this article is with a diagram. The nodes involved are the client apps that will access our APIs, the apiman API Gateway, and the servers that host our APIs: + +![apiman logo](/blog/images/2015-08-03/apiman_security-redux.png) + + Let’s work our way through the diagram from left to right and start by taking a look at Policy Level Security. + +##Policy Level Security + +apiman includes several pre-defined policies OOTB. The policies provide support for controlling access to APIs based on the rate at which the APIs are invoked, the IP address of the client apps that access the APIs, authorization, and authentication. In the most recent article in this series, we showed how to configure an authentication policy. To keep things simple, we chose BASIC authentication. This BASIC Authentication policy provides security for the communication channel between the client apps and the apiman API Gateway. An incoming request to the API Gateway from a client initiates the policy chain, the policy is applied and the client is requested to supply a username and password. The level of security provided by this policy can be enhanced if the policy is configured with SSL encryption. + +But, this policy level security only secures the left side of the diagram, that is the communication channel between the client apps and the API Gateway. In this communication channel, the client apps play the role of the client, and the API Gateway plays the role of the server. + +We also want to secure the right side of the diagram, where the API Gateway plays the role of a client, and the APIs play the role of the servers. + +(It’s also worth noting that while policy security protects the managed API, it does nothing to protect the unmanaged API as this API can be reached directly, without going through the API Gateway. This is illustrated by the red line in the diagram. So, while access to the managed API through the apiman API Gateway is secure, policy security does not secure the unmanaged API endpoint.) + +##Endpoint Level Security + +In contrast to policy level security, with endpoint security we are securing the right side of the diagram. + + A recent post by Marc Savy to the apiman blog [http://www.apiman.io/blog/gateway/security/mutual-auth/ssl/mtls/2015/06/16/mtls-mutual-auth.html](http://www.apiman.io/blog/gateway/security/mutual-auth/ssl/mtls/2015/06/16/mtls-mutual-auth.html) described how to configure Mutually Authenticated TLS (Transport Layer Security) between the API Gateway and the managed APIs. With Mutual TLS, bi-direction authentication is configured so that the identities of both the client and server are verified before a connection can be made. + +In setting up Mutual TLS, keystores, containing a node’s private key, and truststores, containing public certificates to govern the other nodes that the node should trust, were created. The API Gateway was configured in its apiman.properties file to reference the keystores and truststores. The API was configured with mutual authentication by setting the API Security dropdown in the Implementation tab to MTLS/Two-Way-SSL. Finally, the API was programmed with mutual authentication enabled. With Mutual TLS configured, the communication channel on the right side of the diagram, from the API Gateway to the APIs, was made secure. + +We should also note that, unlike policy security, endpoint security also secures the APIs from attempts to bypass the API Gateway. With Mutual TLS, a two-way trust pattern is created. The API Gateway trusts the APIs and the APIs trust the API Gateway. The APIs, however, do not trust the client apps. As is shown by the large “X” character that indicates that a client app cannot bypass the API Gateway and access the APIs directly. + +One last point that is important to remember is that the endpoint level of security applies to all requests made to the APIs, regardless of whatever policies are configured. + +##Compare and Contrast + +To summarize, the differences between policy level security and endpoint level security are: + +| Policy Level Security | End Point Level Security | +| ------------------------ | ------------------------ | +| Secures communications between the client apps (clients) and API Gateway (server) | Secures communications between the API Gateway (client) and APIs (servers) | +| Configured in an API Gateway policy | Configured for the API Gateway as a whole in apiman.properties and with key/certificates infrastructure | +| Applied by the policy at runtime | Applied for all API requests, regardless of the policies configured for an API | +| Does not secure the unmanaged API from access by unauthorized clients | Secures the unmanaged API endpoints from access by unauthorized clients | + + +##Author Acknowledgements + + As always, the author would like to acknowledge Marc Savy, Eric Wittmann, and the apiman team for their review comments and suggestions on writing this article! + +## References +* [http://www.apiman.io/blog/gateway/security/mutual-auth/ssl/mtls/2015/06/16/mtls-mutual-auth.html](http://www.apiman.io/blog/gateway/security/mutual-auth/ssl/mtls/2015/06/16/mtls-mutual-auth.html) (written by Marc Savy) +* https://dzone.com/articles/adding-basic-authentication + + + diff --git a/_blog-src/_posts/2015-08-03-policy-endpoint-security.markdown b/_blog-src/_posts/2015-08-03-policy-endpoint-security.markdown index b2d2cc435..b1eb37590 100644 --- a/_blog-src/_posts/2015-08-03-policy-endpoint-security.markdown +++ b/_blog-src/_posts/2015-08-03-policy-endpoint-security.markdown @@ -4,6 +4,7 @@ title: "apiman Policy and Endpoint Security" date: 2015-08-03 11:00:00 author: len_dimaggio categories: security +newUrl: 2015-08-03-policy-endpoint-security-redux --- In this, the fifth article in the series on apiman, JBoss’ new API Management framework, we’ll examine how apiman enables you to provide security for your managed services at the policy level, and and at the endpoint level for its managed and unmanaged endpoints. diff --git a/_blog-src/_posts/2015-08-17-limiting-policies-redux.markdown b/_blog-src/_posts/2015-08-17-limiting-policies-redux.markdown new file mode 100644 index 000000000..ccedaf886 --- /dev/null +++ b/_blog-src/_posts/2015-08-17-limiting-policies-redux.markdown @@ -0,0 +1,52 @@ +--- +layout: post +title: "apiman Limiting Policies" +date: 2015-08-17 11:00:00 +author: len_dimaggio +categories: policies +oldUrl: 2015-08-17-limiting-policies +--- + +In this, the sixth article in the series on apiman, JBoss’ new API Management framework, we’ll examine how apiman enables you to govern access to managed APIs through the use of rate limiting policies. + +The runtime core of apiman is the API Gateway and the policies that it applies to incoming requests to APIs. apiman is configured out of the box with a variety of policies that can be used to govern access to APIs managed by the API Gateway based on IP address, user authentication, and usage levels. From its first release, apiman has supported rate limiting policies, where the upper limit for use of an API could be governed by a policy. In its new 1.1.6 release, apiman has expanded this support to include quota based limiting policies. + + + +##Types of Limiting Policies + +As of release 1.1.6, apiman supports these types of limiting policies: + +* Rate Limiting - This policy type governs the number of times requests are made to an API within a specified time period. The requests can be filtered by user, client app, or API and can set the level of granularity for the time period to second, minute, hour, day, month, or year. The intended use of this policy type is for fine grained processing (e.g., 10 requests per second). +* Quota - This policy type performs the same basic functionality as the Rate Limiting policy type., however, the intended use of this policy type is for less fine grained processing (e.g., 10,000 requests per month). +* Transfer Quota - In contrast to the other policy types, Transfer Quota tracks the number of bytes transferred (either uploaded or downloaded) rather than the total number of requests made. + +Each of these policies, if used singly, can be effective in throttling requests. apiman, however, adds an additional layer of flexibility to your use of these policy types by enabling you to use them in combinations. Let's look at a few examples. + +##Combinations of Limiting Policies = Flexibility + +Limiting the total number of API requests within a period of time, is a straightforward task as this can be configured in a quota policy. This policy, however, may not have the desired effect as the quota may be reached early in the defined time period. If this happens, the requests made to the API during the remainder of the time period will be blocked by the policy. A better way to deal with a situation like this is to implement a more flexible approach where the monthly quota policy is combined with a fine grained rate limiting policy that will act as a throttle on the traffic. + +To illustrate, there are about 2.5 million seconds in a month. If we want to set the API request quota for a month to .5 million, then we can also set a rate limit policy to a limit of 5 requests per second to ensure that API requests are throttled and the API can be accessed throughout the entire month. + +Here’s a visual view of a rate limiting policy based on a time period of one week. If we define a weekly quota, there is no guarantee that users will not consume that quota before the week is over. This will result in an API requests being denied at the end of the week: + +![rate limit coarse grain](/blog/images/2015-08-17/rate_limit1-redux.png) + +In contrast, if we augment the weekly quota with a more fine grained policy, we can maintain the API’s ability to respond to requests throughout the week: + +![rate limit fine grain](/blog/images/2015-08-17/rate_limit2-redux.png) + +The ability to throttle API requests based on API request counts and bytes transferred provides even greater flexibility in implementing policies. APIs that transfer larger amounts of data, but rely on fewer API requests can have that data transfer throttled on a per byte basis. For example, an API that is data intensive, will return a large amount of data in response to each API request. The API may only receive a request a few hundreds of times a day, but each request may result in several megabytes of data being transferred. Let's say that we want to limit the amount of data transferred to 6GB per hour. For this type of API, we could set a rate limiting policy to allow for one request per minute, and then augment that policy with a transfer quota policy of 100Mb per hour. + +##Summary + +When you configure limiting policies with apiman, it's important to remember that the limits you set can not only function as hard limits for API requests, they can also be used to throttle API requests. This throttling gives you the flexibility to control the level of incoming API requests over a period of time that you designate in the policies without blocking all incoming API requests. The flexibility that apiman provides you in configuring limiting policies is further enhanced by its support for you to create combinations of limiting policies. These combined policies work together to give you both coarse grained and fine grained control over incoming API requests. + +##Author Acknowledgements + +As always, the author would like to acknowledge Eric Wittmann, and the apiman team for their review comments and suggestions on writing this article! + + + + diff --git a/_blog-src/_posts/2015-08-17-limiting-policies.markdown b/_blog-src/_posts/2015-08-17-limiting-policies.markdown index 9cfbe9f68..8917513ba 100644 --- a/_blog-src/_posts/2015-08-17-limiting-policies.markdown +++ b/_blog-src/_posts/2015-08-17-limiting-policies.markdown @@ -4,6 +4,7 @@ title: "apiman Limiting Policies" date: 2015-08-17 11:00:00 author: len_dimaggio categories: policies +newUrl: 2015-08-17-limiting-policies-redux --- In this, the sixth article in the series on apiman, JBoss’ new API Management framework, we’ll examine how apiman enables you to govern access to managed services through the use of rate limiting policies. diff --git a/_blog-src/images/2015-01-09/apiman_3-redux.png b/_blog-src/images/2015-01-09/apiman_3-redux.png new file mode 100644 index 000000000..d1e83c137 Binary files /dev/null and b/_blog-src/images/2015-01-09/apiman_3-redux.png differ diff --git a/_blog-src/images/2015-01-09/apiman_4-redux.png b/_blog-src/images/2015-01-09/apiman_4-redux.png new file mode 100644 index 000000000..b47910dab Binary files /dev/null and b/_blog-src/images/2015-01-09/apiman_4-redux.png differ diff --git a/_blog-src/images/2015-08-03/apiman_security-redux.png b/_blog-src/images/2015-08-03/apiman_security-redux.png new file mode 100644 index 000000000..a471e937b Binary files /dev/null and b/_blog-src/images/2015-08-03/apiman_security-redux.png differ diff --git a/_blog-src/images/2015-08-17/rate_limit1-redux.png b/_blog-src/images/2015-08-17/rate_limit1-redux.png new file mode 100644 index 000000000..e144049bc Binary files /dev/null and b/_blog-src/images/2015-08-17/rate_limit1-redux.png differ diff --git a/_blog-src/images/2015-08-17/rate_limit2-redux.png b/_blog-src/images/2015-08-17/rate_limit2-redux.png new file mode 100644 index 000000000..c8bfd4153 Binary files /dev/null and b/_blog-src/images/2015-08-17/rate_limit2-redux.png differ diff --git a/_blog-src/index.html b/_blog-src/index.html index 0273e4ce1..322b97499 100644 --- a/_blog-src/index.html +++ b/_blog-src/index.html @@ -6,6 +6,7 @@

Blog Posts subscribe

{% for post in site.posts %} + {% if post.newUrl == nil %} {% assign author = site.data.authors[post.author] %}
@@ -23,6 +24,7 @@

{{ post.title }}

+ {% endif %} {% endfor %}