i want to send sms to user mobile number using third-party REST service inside a Spring boot application.
API like follow:
http://cloud.smsindiahub.in/vendorsms/pushsms.aspx?user=abc&password=xyz&msisdn=919898xxxxxx&sid=SenderId&msg=test%20message&fl=0&gwid=2
user: Your login username.
password: Your login password.
msisdn: Single mobile number
sid: Approved sender id(Only 6 characters).
msg: Your message content(Minimum 459 characters/3 messages). Note: If you are using template then edit only the dynamic part which is in ##Field##.
fl: if flash message then 1 or else 0
gwid: 2 (its for Transactions route.)
Note: Only 100 mobile numbers are allowed.
So i want to ask can i do using RestTemplate or any other way better in spring boot?
also i want to save response which like below which is josn response:
{"ErrorCode":"000","ErrorMessage":"Success","JobId":"381a8090-b230-42fa-ac04-157cc2142bfa","MessageData":[{"MobileNumber":"919898xxxxxx ","MessageParts":[{"MessageId": "919898xxxxxx -67e3765cdf034f438a432eacb88d0c14","MessagePartId":1,"MessageText":"test message"}]}]}
and for REST API username and password saving application.xml is secure?also how to save and access in class.
if any example for the same just send me link.
thanks.
First, Your API provider should a different authentication method like Auth key as using username and password in RestAPI is not good option.
Now, You can call 3rd party RestAPI url in springboot as below:
private static void custom_func()
{
final String uri = "http://cloud.smsindiahub.in/vendorsms/pushsms.aspx?user=abc&password=xyz&msisdn=919898xxxxxx&sid=SenderId&msg=test%20message&fl=0&gwid=2";
RestTemplate restTemplate = new RestTemplate();
String result = restTemplate.getForObject(uri, String.class);
System.out.println(result);
}
Related
I have a Spring-based webapp that uses JavaMail to send and process mail via SMPT/IMAP.
I now need to add support for OAuth2 authentication, initially for GMail.
The webapp already uses Spring Security, so I've tried to integrate spring-security-oauth2-client 5.8.1
The objecive is:
user enters mail server details, and indicates that it should connect using OAuth2
on completion, a new browser window opens with a Spring Security URL e.g. http://localhost:8080/myapp/oauth/gmail
Spring Security redirects to Google to perform the authentication
Google redirects back to http://localhost:8080/myapp/oauth2/code/gmail
The access token and refresh token are received and stored, with the email address of the GMail account used as the principal
This works up to a point. In step 5, the OAuth2AuthorizationCodeGrantFilter uses securityContextHolderStrategy.getContext().getAuthentication() to get the principal prior to storing the token. In my case, this is the app user.
How can I make it the email address of the GMail user?
Is there a way to populate the OAuth2AuthorizationCodeGrantFilter with a different SecurityContextHolderStrategy via Spring-XML?
OAuth2AuthorizationCodeGrantFilter.processAuthorizationResponse():
...
Authentication currentAuthentication = this.securityContextHolderStrategy.getContext().getAuthentication();
String principalName = (currentAuthentication != null) ? currentAuthentication.getName() : "anonymousUser";
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(
authenticationResult.getClientRegistration(), principalName, authenticationResult.getAccessToken(),
authenticationResult.getRefreshToken());
this.authorizedClientRepository.saveAuthorizedClient(authorizedClient, currentAuthentication, request,
response);
...
I have a multi-tenant application (springboot keycloak adapter + spring security) secured by Keycloak. Given the multi-tenant nature of the project, I wrote a multi-client connector which works fine.
On the official Keycloak doc, it is recommended (for multi-tenant applications) to model each tenant as a new realm, but for me it works better to have multiple clients within the same same realm. This is due to following advantages:
Client scopes, groups and other configs can be shared
Users don't need to be duplicated on N different realms
SSO login works perfectly within same realm clients (by using bearer
services +CORS)
So, everything works fine except for 1 thing, my initial SSO access_token (which is then shared across all bearer-only services by means of CORS) is kind of big (it shows all the resources - tenants - and its roles within each resource/tenant).
I'd like to limit the size of the access_token, by means of using "scopes" to restrict the roles in the token to only those meaningful to the tenant where I'm logged in at that time. For this, I'm manually firing a Request to the auth server (outside of the standard functionality provided by springboot/spring security) with the goal of manually overwriting whatever access-token exists within my app, with the new one generated by my extra request.
My "new" token request looks similar to this:
SimpleKeycloakAccount currentUserAccount = (SimpleKeycloakAccount) auth.getDetails();
String authServerUrl = currentUserAccount.getKeycloakSecurityContext().getDeployment().getAuthServerBaseUrl();
String realm = currentUserAccount.getKeycloakSecurityContext().getDeployment().getRealm();
String resource = currentUserAccount.getKeycloakSecurityContext().getDeployment().getResourceName();
String refreshToken = currentUserAccount.getKeycloakSecurityContext().getRefreshToken();
String token = currentUserAccount.getKeycloakSecurityContext().getTokenString();
Http http = new Http( new Configuration(authServerUrl, realm, resource,
currentUserAccount.getKeycloakSecurityContext().getDeployment().getResourceCredentials()
, null),
(params, headers) -> {});
String url = authServerUrl + "/realms/" + realm + "/protocol/openid-connect/token";
AccessTokenResponse response = http.<AccessTokenResponse>post(url)
.authentication()
.client()
.form()
.param("grant_type", "refresh_token")
.param("refresh_token", refreshToken)
.param("client_id", resource)
.param("client_secret", "SOME_SECRET")
.param("scope", "SOME_SCOPE_TO_RESTRICT_ROLES")
.response()
.json(AccessTokenResponse.class)
.execute();
// :) - response.getToken() and response.getRefreshToken(), contain new successfully generated tokens
My question is, how can I force my-app to change/reset the standard access-token & refresh_token obtained by the usual means, with these "custom created" tokens? or is that possible at all?
Thx for any feedback!
Further Information
To clarify more, lets analyze the behavior of a typical springboot/spring security project integrated with Keycloak:
You protect your endpoints with "roles" via configurations (either on the application.properties, or on the SecurityContext)
You know that this Spring application talks in the back channel with the Keycloak authorization server, that's how you become the access_token (But all this is a black box for the developer, you only know a Principal was created, a Security Context, Credentials; etc - everything happens behind the curtains)
Considering those 2 points above, imagine that you use an Http library to basically request a new token towards the auth server token endpoint like in the code above (yes filtered by scopes and everything). So the situation now is that though you have created a valid access_token (and refresh_token); since they were created "manually" by firing a request towards the token endpoint, this new token hasn't been "incorporated" to the application because No new Principal has been created, no new security context has been generated, etc. In other words, to the springboot application this new token is non-existent.
What I'm trying to accomplish is to tell sprinboot/spring security: "Hey pal, I know you didn't generate this token yourself, but please accept it and behave as if you'd have created it".
I hope this clarifies the intent of my question.
You can revoke a token using org.springframework.security.oauth2.provider.token.ConsumerTokenServices#revokeToken method.
On the Autorization Server:
#Resource(name="tokenServices")
ConsumerTokenServices tokenServices;
#RequestMapping(method = RequestMethod.POST, value = "/tokens/revoke/{tokenId:.*}")
#ResponseBody
public String revokeToken(#PathVariable String tokenId) {
tokenServices.revokeToken(tokenId);
return tokenId;
}
Of course, you'll have to secure this method since is a very sensitive one.
In the case that each tenant is a separate client you can just use keycloak's "Scope" mapping at each client. Just turn off Full Scope Allowed and your tokens will only contain the user's roles for that specific client (tenant).
"Scope Mappings" is a a non intuitive way of saying "Define what roles should go into the access token" :-)
When turned off the UI changes and you even can configure what other roles of other clients should additionally go into the access token.
Just to give some closure to this question:
No, there doesn't seem to be any elegant or intended way to force a manual token renewal by means of using springboot/spring security keycloak connector.
The Javascript connector can do this trivially like this:
// for creating your keycloak connector
var keycloak = Keycloak({
url: 'http://localhost:8080/auth',
realm: '[YOUR_REALM]',
clientId: '[YOUR_CLIENT]'
});
// for login in (change scopes list to change access capabilities)
var options = {
scope: [EMPTY_STRING_SEPARATED_LIST_OF_SCOPES] // <-- here specify valid scopes
};
keycloak.login(options); // <-- receive a new token with correctly processed scopes
Given how easy it is to do this with the Keycloak client JS adapter, and how obscure it is to do this with the springboot/spring security adapter, it follows following:
Security design seems intended to have 2 (Keycloak security) layers; the first is a front-facing public client (usually password protected), and the 2nd layer is composed of several bearer-only services which would ussually only accept acces-tokens. If for those bearer-only services you want to implement finner grained control via scopes, you achieve that trivially by using a javascript based Keycloak client (other connectors as explained won't deal nicely with the header modification necessary to deal with OAuth2 scopes).
I created a spring boot service that is secured by the spring-security-keycloak-adapter. As the service already knows about the (keycloak) identity provider, I don't see any point in sending the issuerUrl and clientId to the mobile client to login directly into keycloak. Instead, I want to simply call the loginurl of the service in a webview on the client. In my understanding spring should redirect to keycloak and in the end return the token.
Unfortunately all flutter packages require the clientId and issuerUrl for the oauth process
I alread tried the openid_client package for flutter
As your can see in the following code example from the official repository it requires the clientId and issuerUrl
// import the io version
import 'package:openid_client/openid_client_io.dart';
authenticate(Uri uri, String clientId, List<String> scopes) async {
// create the client
var issuer = await Issuer.discover(uri);
var client = new Client(issuer, clientId);
// create an authenticator
var authenticator = new Authenticator(client,
scopes: scopes,
port: 4000);
// starts the authentication
var c = await authenticator.authorize(); // this will open a browser
// return the user info
return await c.getUserInfo();
}
Full disclosure: I didn't write Flutter, but I did write some of the related client code for Spring Security.
Why issuerUri? The reason for this is likely for OIDC Discovery. You can use the issuer to infer the other authorization server endpoints. This cuts down on configuration for you: You don't need to specify the token endpoint, the authorization endpoint, and on and on. If you supply only the issuer, then flutter figures out the rest.
Note that with Spring Security, this is just one configuration option among multiple, but something needs to be specified either way so the app knows where to go. I can't speak for flutter, but it may just be a matter of time before it supports more configuration modes.
Why clientId? This is a security measure and is required by the specification. If someone is calling my API, I want to know who it is. Additionally, authorization servers will use this client_id to do things like make sure that the redirect_uri in the /authorize request matches what is configured for that client_id.
In my Spring MVC application I am using spring security. It works fine so far, but I have to admit, I do not understand all the details.
In the same application the user can call some controller functions by rest api. When the user (lets say Tom) does this, his authentication is lost. Instead the controller is called by user anonymous.
I tracked down that "user switch" to the code below. Variable restCall contains an url to my application. That call would work for user Tom, if he would place it in the browser directly. Using the restcall, the user changes to anyonymous.
1) Can I prevent that, when the calling User (Tom) was already logged in?
2) As those services should be called by a user that is not already browsing the web interface of the application, I would have to find a way to login by the rest call itself.
private void callWebservice(HttpServletRequest req, String restCall) {
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response
= restTemplate.getForEntity(restCall, String.class);
logger.debug(response.toString());
//assertThat(response.getStatusCode(), equalTo(HttpStatus.OK));
}
You need, for example, a JSON Web Token (JWT) Authentication.
Steps are the following:
1) Client does an authentication, a post request with username and password
2) If authentication is successful, server returns a token in which is coded the user
3) In your next call, GET or POST, you add JWT to your header, this way the server will know who you are, because server can decode the token, and can grant also the right authorities and functionalities
I've found similar issue but it's unanswered, so I suppose I'm going to duplicate question a little.
I am using Spring OAuth2 to implement separate resource and custom authentification servers.
I've already configured interaction with auth server through issuing&validating JWT tokens and everything seems fine.
Now I'm trying to add SSO functionality but really stuck with it. I've researched the official Spring examples and attached guide but it is very short worded when it comes to connecting SSO part with custom server authentication. And actually author uses only external provider resource ('user' info) to show process.
I think it is normal thing to have all this SSO means of authentication and also custom registration. I can see it works well with stackoverflow for example.
I am loking for directions where to find any info about handling on resource server different kind of tokens issued by multiply SSO providers and also from custom auth server.
Maybe I can use auth chain to do this and some mean to distinguish token format to know how to process it. Is it possible with Spring OAuth2? Or I need to do this magic somehow manually?
For now I have just one 'maybe strange' idea:
To not involve my own resource server with this SSO stuff at all. After receiving Facebook (for example) token - just exchange it for api JWT token with custom auth server (associating or creating user on the way) and then work with resource server on standard basics
EDITED:
I've found at least something. I've read about configuring filters in authorization chain and translate given social tokens to my custom JWT-s as 'post authenticate'(not a crazy idea after all). But it mostly done with SpringSocial.
So now question is: how to do that?
Forgot to say that I am using Password Grant for authentication on custom server. Clients will be only trusted application and I do not even sure about browser client (thinking about only native mobile options). Even if I decide to have browser client I'll make sure it's going to have backend to store sencetive information
Ok, so after struggling to implement such behavior I've stuck with two different libraries (Spring Social & OAuth2). I decided to go my own way and do it with just Spring OAuth2:
I have the resource server, authentication server and client(backed up by Java and uses OAuth2 Client library, but it can be any other client) - my resources can be consumed only with my own JWT auth token given by my own auth server
in a case of a custom registration: client obtains JWT token(with refresh token) from auth server and sends it to the res server. Res server validates it with public key and gives the resource back
in a case of SSO: client obtains Facebook(or other social platform token) and exchanges it for my custom JWT token with my custom auth server. I've implemented this on my auth server using custom SocialTokenGranter(currently handles facebook social token only. For every social network I'll need separate grant type). This class makes an additional call to facebook auth server to validate token and obtain user info. Then it retrieves the social user from my db or creates new and returns JWT token back to the client. No user merging is done by now. it is out of scope for now.
public class SocialTokenGranter extends AbstractTokenGranter {
private static final String GRANT_TYPE = "facebook_social";
GiraffeUserDetailsService giraffeUserDetailsService; // custom UserDetails service
SocialTokenGranter(
GiraffeUserDetailsService giraffeUserDetailsService,
AuthorizationServerTokenServices tokenServices,
OAuth2RequestFactory defaultOauth2RequestFactory,
ClientDetailsService clientDetailsService) {
super(tokenServices, clientDetailsService, defaultOauth2RequestFactory, GRANT_TYPE);
this.giraffeUserDetailsService = giraffeUserDetailsService;
}
#Override
protected OAuth2Authentication getOAuth2Authentication(ClientDetails clientDetails, TokenRequest request) {
// retrieve social token sent by the client
Map<String, String> parameters = request.getRequestParameters();
String socialToken = parameters.get("social_token");
//validate social token and receive user information from external authentication server
String url = "https://graph.facebook.com/me?access_token=" + socialToken;
Authentication userAuth = null;
try {
ResponseEntity<FacebookUserInformation> response = new RestTemplate().getForEntity(url, FacebookUserInformation.class);
if (response.getStatusCode().is4xxClientError()) throw new GiraffeException.InvalidOrExpiredSocialToken();
FacebookUserInformation userInformation = response.getBody();
GiraffeUserDetails giraffeSocialUserDetails = giraffeUserDetailsService.loadOrCreateSocialUser(userInformation.getId(), userInformation.getEmail(), User.SocialProvider.FACEBOOK);
userAuth = new UsernamePasswordAuthenticationToken(giraffeSocialUserDetails, "N/A", giraffeSocialUserDetails.getAuthorities());
} catch (GiraffeException.InvalidOrExpiredSocialToken | GiraffeException.UnableToValidateSocialUserInformation e) {
// log the stacktrace
}
return new OAuth2Authentication(request.createOAuth2Request(clientDetails), userAuth);
}
private static class FacebookUserInformation {
private String id;
private String email;
// getters, setters, constructor
}
}
And from class extending AuthorizationServerConfigurerAdapter:
private TokenGranter tokenGranter(AuthorizationServerEndpointsConfigurer endpoints) {
List<TokenGranter> granters = new ArrayList<>(Arrays.asList(endpoints.getTokenGranter()));
granters.add(new SocialTokenGranter(giraffeUserDetailsService, endpoints.getTokenServices(), endpoints.getOAuth2RequestFactory(), endpoints.getClientDetailsService()));
return new CompositeTokenGranter(granters);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer
...
.allowFormAuthenticationForClients() // to allow sending parameters as form fields
...
}
Every JWT token request is going to 'host:port + /oauth/token' url
Depending on 'Grant type' the server will handle such requests differently. Currently I have 'password'(default), 'refresh_token' and 'facebook_social'(custom) grant types
For default 'password' Grant type the client should send next parameters:
clientId
clientSecret (depends of the client type. Not for single-page clients)
username
password
scope (if not explicitly set in auth server configuration for current client)
grantType
For 'refresh_token' Grant type the client should send next parameters:
clientId
clientSecret (depends of the client type. Not for single-page clients)
refresh_token
grantType
For 'facebook_social' Grant type the client should send next parameters:
clientId
facebook_social_token (custom field)
grantType
Based on the client design the way to send these requests will be different.
In my case with test Java based client which uses Spring OAuth2 library to obtain the social token I do the token exchange procedure with the redirect in controller(controller being invoked using url defined in facebook dev page configuration).
It can be handled in two stages: after obtaining facebook social token JavaScript can make a separate explicit call to my auth server to exchange tokens.
You can see Java client implementation examples here, but I doubt that you're going to use Java client in production:https://spring.io/guides/tutorials/spring-boot-oauth2/