Basics of the cloud-native system:
In real-time applications, we usually build a cloud-native system and also build a system that is easy to scale, it's agile, it is a, it takes advantage of the elasticity of a cloud environment and it can scale-out. It is robust in the face of errors or service outages or topology changes, and its observable, both at the service level and the system level. Now, in this blog, I have explained how to secure that edge service. So, I have created an available edge service, and it's exposed to the outside world. You may not need it authenticated. You may not need it protected, but it is always a good idea to protect it if you do need it.
Usernames and passwords don't scale in the Microservice and distributed systems worlds. They don't handle the concept of a client, and they have several restrictions when working with distributed systems. So, in this section, I've explained how to get over the limits of usernames and passwords. Usernames and passwords are a useful way to express who is making a system request, and we can deduce that if that person has permission to use the system, then the requester has all of that user's authorization.
However, in a world where you have a variety of clients, this isn't practical. I'm not going to use the same client to access the same service. For example, I can access my facebook.com account on my iPhone rather than my web browser or, you know, my Android device or my TV. All of these clients are distinct, have different security requirements, and can provide higher degrees of trust and confidence.
As a result, we must address this. The variety of clients in a Microservice environment causes a lot of challenges, thus we need something that recognizes the nature of each client. Simply stating that this is a specific user making a request is insufficient. You must be aware that this is a specific user who is requesting his iPhone, and we must also be able to handle various forms of client interactions, as different clients have different workflows.
OAuth2 Real-time Use Cases:
- Let me give you some specific examples to illustrate my point. Consider the following scenario: Facebook.com as a domain name it’s fairly normal to go on the internet and discover, you come across a sign-in with a Facebook button on a third-party website, click it, and it takes you to facebook.com, where it asks you to accept this third-party website accessing your information? Do you want to grant it permission to read your email, post to your Facebook wall, and look at your Facebook friend graph? You say yes, and when you press the button, which sends you back to the third-party site with an access token. The third-party website can now communicate with the Facebook APIs and receive access tokens.
- This access token represents you and acts on your behalf. On your behalf, it beards. It's referred to as a bearer token, and it's an OAuth bearer token. The benefit of using a token is that the login and password you provide on facebook.com are sent to a trustworthy domain. When you visit facebook.com in your browser, you will see the padlock or the lock icon. It demonstrates that you have a certificate. It shows that the service is secure, that it's HTTP, that everything is safe and secure, and that you don't have to worry about a third-party website having your Facebook account and password.
- You don't want your username and password to fall into their hands. Maybe you trust them right now, but maybe they'll get hacked tomorrow.
- You don't want a nasty scammer misusing your account information, and they can't do it today because all they have is the access token, which you can cancel at any time by logging into your facebook.com account. You can even specify the rights that token is permitted to have. They may just be allowed to read your email, but other clients with whom you have a higher level of confidence are allowed to write on your wall as well.
- Permission levels differ from one client to the next. Isn't this an example of a common interaction? You're using a third-party website that you don't completely trust. You want to limit the extent of their permissions, as well as the amount of time you spend relying on usernames and passwords. In this situation, the username and password are only ever sent from the browser on facebook.com to facebook.com via an SSL endpoint. There's no chance it'll fall into the wrong hands.
- Let's have a look at a different type of engagement. Let's pretend you're a Facebook.com developer. This is no longer a third-party application. You're creating the Facebook app experience for the iPhone on behalf of Facebook. Do you think the Facebook App should redirect to facebook.com and ask you, the user, for permission to access your facebook.com information? Isn't that a bit clumsy of a user experience?
- That's a bad experience, and there's no reason for it because it doesn't matter. Your password is already in the hands of Facebook app developers. Your username and personal details are already in their possession. They are employed at Facebook.com. They have access to the databases in the same way that the website itself does. In this instance, it's far more practical to simply sign in. Simply provide a username and password in Chrome, then enter the application to receive a token.
- So, once again, the token is useful because it allows you to cancel access to a certain client without locking out all of the other clients if, for example, your phone is stolen. They are under no obligation to update your password.
- You are not breaking any other clients or anything else; you are simply restricting access to that one client. So, in this scenario, we'll need different kinds of interaction models, different kinds of authentication methods, and we'll need to be able to handle all of these diverse use cases in a unified manner. Usernames and passwords do not provide us with anything.
How to secure your Java Microservice using Spring Security OAuth2?
- What I am going to explain is something called OAuth. OAuth is an open specification. There are three different versions of it. 1.0, 1.0A, and 2.0. We're going to look at something called Spring Security OAuth and Spring Security builds on top of Spring Security. Here, I want to protect our edge service. We want to say that whenever there's a request that comes in, it should have an access token, and if it doesn't have an access token, we want to reject that request. We need to stand up something called an auth service so that when the token comes in the reservation client can call the auth service and say is this a valid token? Is this a valid user?
- Let's use security, Spring Cloud Security. We're going to use H2, the in-memory embedded database to store some default usernames and passwords, just some users for our accounts. You might have a proper database here, but I have used a simple JPA-based setup. Again, we're going to use Spring Security. We're going to use Spring Security here, so we don't have to use H2 for our database. We can talk to anything that Spring Security could talk to.
- It could be Active Directory or LDAP or PAM or Kerberos or whatever. OAuth itself doesn't care where the information about the users comes from. OAuth is a security deferral technology. It defers the question of authentication to some other service. All it does is it, once it has the confirmation from the underlying or backing security technology, it manages the access to that token. It vends tokens and it revokes them and it manages the lifecycle of that token.
- In this blog, I have implemented the Spring Security user detail service. We're going to do so in terms of JPA and H2. We're going to use web support. I have used OAuth dependencies as well. With all these dependencies you can generate the project in hire Spring boot developers. Then I have created an application.properties file with the configurations: spring.application.name equals aegis-auth-service and then added the property “spring.cloud.config.uri =http://localhost:8081. This is nothing but my local config server url. I am going to open up the build here and we're going to bring in the spring-cloud-starter-config dependency. I have taken spring-cloud-starter-eureka dependency as well.
- We're going to do the normal pro forma sort of thing and we need this property file to be bootstrap.properties. Then we're going to open up the AuthService code. We have to enable service registration and discovery and hence we will be using @EnableDiscoveryClient and we now need to feed Spring Security about our usernames and passwords.
- Here in this blog, I have created a JPA-based solution here with a simple set of default users. I am going to create an entity called UserAccount and in that, we have to give the account ID, a username and a password, and a private boolean field called isAccountActive. This field tells user whether the account is allowed or not, basically, I am going to give it an ID, an auto-incrementing surrogate primary key value here, and we'll create some getters.
- Here's this. Now we need some way to store and persist and interact with that entity. So, I have created a Spring data repository. I have created UserAccRepository interface that extends JpaRepository managing entities of type Account whose primary keys of type Long.
OAuth2 Example Implementation with Java Microservices Using GitHub as Resource Server:
- Here, I have shown here how to answer the question given a username, what is the information about that user. We are going to implement a user details service type here. This is an API inside of Spring Security, and this interface has one job. When asked, what is your username, will respond with the appropriate user details. Now the UserAccDetails object in Spring Security is a wrapper object, and there are a few different implementations, but the implementation of UserAccDetails is fairly straightforward.
- The username and password are self-explanatory, and then the collection of granted authorities refers to basically a collection of strings. Alright, a granted authority is just a wrapper around a string, and it may mean different things in your underlying system. You might have roles and scopes and permissions and claims and whatever. If you're talking to different security technologies, these are different things but suffice it to say, there's usually some notion of an authority in your system. We have to satisfy this constraint. To do that, we're going to run a query. Find me all the accounts by this username. We'll have Spring Data do that heavy work for us.
- We'll build a finder method here by username, and we'll return an object of type optional. Java Eight is optional, so it says if there's a value we'll return it. If not, we'll return an empty bucket, and we can interrogate that, as opposed to a null. There we go. We'll say this.accountRepository.findByUsername, passing in the username, and our job is to say if we cannot find it, we're going to throw an exception. That's the contract here. We have to throw an exception if we cannot find it.
- In our Springboot application, whenever a request comes in, I need to exchange the token by going to the value here. Its security.oauth2.resource.userInfoUri, and this is pointing to our authorization server on localhost: 9191/get/user. Let's grab this access token and let's try and make a request to the reservation client that's not authenticated, and this should fail. Let's say reservations/names. Full authentication is required to access this resource, as we would expect. Let's now add in an authorization header. I'll say -H"authorization: bearer, paste. Make a request, and then voila. There are all of the names that we've added to the system. Now we can prove that this is working by tampering with the request.
- We can just muddle with it. Let's remove some important keys. There we go. Invalid token. Now we've successfully secured our end service. All requests to the end service will go to the authorization server to ascertain the validity of the request and the requester. This is very, very powerful. We can use those other flows as well. We can use, for example, the authorization code flow.
- If we wanted to, Spring Cloud Security also supports the SSO flow, where you login on the front-end web app, web application, maybe an angular.js, or a React-based single-page application, and then you enter the username and password, it redirects to the website, it asks you if you approve of these scopes, and then it redirects you back. That's also supported as well by using the @EnableSSO annotation.
Step by Step Code implementation (GitHub as resource Server):
- Scenario: User will choose GitHub account for Singin purpose and then request will from the client application will go to the GitHub authentication server with request payload as client_id and then from authentication server request will delegate to the GitHub authorization server with the same request client id and then GitHub sends an access token to the User/client.
- With same access token, a client sends another request to the GitHub resource server. The GitHub resource server will decrypt that access token and it will provide useful details to the client application.
- Once the user gets authorized, it sends access token to client and the same accesstoken client needs to pass as an authorization header so that resource server will decrypt that token and validate that.
- To add the spring OAuth specific packages/classes, we have to include “spring-cloud-starter-oauth2” dependency in our pom.xml file.
- Next, we have to create our Springboot main class where need to use @EnableOAuth2Sso annotation. I have created a class called ProvisioningApplication. Java were used the OAuth annotation with a single sign-on as below:
- Here, we will be exposing a rest endpoint so that we can confirm when the user sends the request to our application then whether the call is redirecting to GitHub server or not.
- Let’s create a rest controller and will create a rest endpoint with GetMapping and in this class, I have created a method called getMessage() where I am just returning the hello User Message with the username. Below is the client-side application:
- Now we are done with client side application and let's go the syncing part with GitHub. Go to the GitHub dashboard and then click on profile-> settings-> developer setting and then navigate to OAuth Apps. Please refer to below screenshot.
- Here, you need to create one application so that we can get the client ID and secret. From our application based upon the client id, we can communicate to GitHub server. The next step is you will be landing on the GitHub Apps page where you have to click on “Oauth Apps”.
- Here, on this page, you have to create one application in giuthub so that we can get the ClientID and secretID. So, from our application based on the clientid, we can communicate to the GitHub server. So, you have to click on the “Register a new application”. And then on the next page, you have to give application name that we created in our local project. You can choose a different name as well not an issue. And then in the homepage url field, give any default url. I have given http://localhost:9090.
- Then on the same page, you have to give the callback url as well. I have given the same url as homepage url. Please refer to the below screenshot:
- Now once you register this application with above settings then in the next page you will get the ClientID and secret as below and with these two fields from our application, we can communicate to GitHub. You can choose a logo from the options. If you choose any logo then you can update the application by clicking update Application setting.
- So, the above ClientID and clientSecret must be added to our code. For that, I have created a yaml file and named it “application.yaml”. In this file we have to add a couple of properties. I have added below ClientID and clientSecret properties. Also, we have to mention accesstoken URL of GitHub. Here you can find that we are delegating to the OAuth2 and through accesstoken. This accesstoken is dynamic.
- Next field is user Authorization url where we have used GitHub login url and in the user-info uri, I am using:https://api.github.com.” ClientID and client secret you have to copy from GitHub UI where you already have generated. In previous section, I already mentioned how to create ClientID and client secret for your application.
- Now, with these configurations, we can sync with GitHub. Now when we run our application locally and then access your url in the browser then it will prompt you to sign in through GitHub and then you have to sign in using your credentials. Once you sign in then you will be prompted with an authentication code to be passed for successful authentication as below:
- After entering the authentication code, you will get another page where you have to authorize your Springboot application so that you can actually hit your actual endpoint and then get the correct output.
Subject: Using Spring Security OAuth2 in a Java Development Outsourcing and Java Microservice application that uses GitHub as a resource server
Ans: Cloud-native system is a system that is easy to scale, it's agile, it takes advantage of the elasticity of a cloud environment and it can scale-out. It is robust in the face of errors or service outages or topology changes, and its observable, both at the service level and the system level.
Ans: You come across a sign-in with a Facebook button on a third-party website, click it, and it takes you to facebook.com, where it asks you to accept this third-party website accessing your information. When you press the button, which sends you back to the third-party site with an access token. The third-party website can now communicate with the Facebook APIs and receive an access token. Actually, this access token represents you and acts on your behalf.
Ans: Spring Security OAuth and Spring Security OAuth builds on top of Spring Security. We want to say that whenever there's a request that comes in, it should have an access token, and if it doesn't have an access token, we want to reject that request. We need to stand up something called an auth service so that when the token comes in the reservation client can call the auth service and say is this a valid token or not or Is this a valid user. Please refer to this blog to know the design of this OAuth2 Springboot microservice
Ans: You must implement a user details service type in this section. This is an API within Spring Security, and this interface only serves one purpose. When asked what your username is, will respond with the relevant user information. The user will select a GitHub account for Singin purposes, and the request will be routed from the client application to the GitHub authentication server with the request payload as the client id, and from the authentication server, the request will be routed to the GitHub authorization server with the same request client id, and finally, GitHub will send an access token to the user/client. With the same access token, a client sends another request to the GitHub resource server. The GitHub resource server will decrypt that access token and it will provide useful details to the client application. Please refer to this blog for detailed coding.