#FrameworkEndpoint to oAuth 2.0 revokeToken - spring-security

I have a #FrameworkEndpoint based controller in order to implement DELETE of token as follows
#FrameworkEndpoint
public class RevokeTokenEndpoint {
#Resource(name = "tokenServices")
ConsumerTokenServices tokenServices;
#RequestMapping(method = RequestMethod.DELETE, value = "/oauth/token")
#ResponseBody
public void revokeToken(HttpServletRequest request) {
String authorization = request.getHeader("Authorization");
if (authorization != null && authorization.contains("Bearer")) {
String tokenId = authorization.substring("Bearer".length() + 1);
System.out.println("tokenId : " + tokenId);
tokenServices.revokeToken(tokenId);
//tokenStore.removeRefreshToken(token);
}
}
}
My request is a DELETE (http://localhost:8081/oauth/token request with Authorization Bearer ce8b914d-57db-4ad7-86d9-be2d7f47b203
The problem is that the end-point does not get hit at all and the message returned back is "unauthorized". When I fire the request with Authorization Basic with client_id and secret then it does hit the end-point. But then in that case I will be forced to pass another parameter or header to carry the token and change the code to get the value of token from this another parameter or header.
I believe, the ideal way would be tell spring security to allow unauthorized calls to remove the access token. Does this make sense ? and if yes then how ?

I have implemented like this
#PostMapping("/token/revoke")
public ResponseEntity<Boolean> revokeToken(
#RequestHeader(value = "Authorization") final String tokenId) {
try {
final String[] token = tokenId.split("\\s+");
tokenServices.revokeToken(token[1]);
return new ResponseEntity<>(true, HttpStatus.OK);
} catch (final Exception e) {
LOGGER.info("Exception while removing access token");
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
tokenId contains Bearer b133b6ee-59db-4809-b546-e47cb879bea1. In this way i have implemented and its working fine

Related

Dart Aqueduct server basic authorization

I'm learning about how authentication works using the Aqueduct framework.
In my channel.dart file I have a route:
router
.route('/protected')
.link(() => Authorizer.basic(validator))
.link(() => ProtectedController());
But I don't know how to create the validator. In the docs I see that I can make a custom Authorizer without using an AuthServer. The code example is this:
class BasicValidator implements AuthValidator {
#override
FutureOr<Authorization> validate<T>(AuthorizationParser<T> parser, T authorizationData, {List<AuthScope> requiredScope}) {}
var user = await userForName(usernameAndPassword.username);
if (user.password == hash(usernameAndPassword.password, user.salt)) {
return Authorization(...);
}
return null;
}
}
I'd like to make a basic working example, but this is the closest that I could get:
class BasicValidator implements AuthValidator {
#override
FutureOr<Authorization> validate<T>(AuthorizationParser<T> parser, T authorizationData, {List<AuthScope> requiredScope}) {
final validUsername = 'bob';
final validPassword = 'password123';
// How do I get the parsed username?
// How do I get the parsed password?
if (parsedUsername == validUsername && parsedPassword == validPassword) {
// How do I create an Authorization?
return Authorization(...);
}
return null;
}
// What is this?
#override
List<APISecurityRequirement> documentRequirementsForAuthorizer(APIDocumentContext context, Authorizer authorizer, {List<AuthScope> scopes}) {
return null;
}
}
Could anyone show me a basic working example of Basic authorization validator?
authorizationData is an instance of AuthBasicCredentials when using Authorizer.basic. An object of this type has username and password fields derived from parsing the 'Authorization' header from a request.
An Authorization object is a container for data related to the authorized resource owner (such as their user ID). It is used by subsequent controllers to control authorization without having to look up the authorized user again; you should populate it with any authorization information you have available.
documentRequirementsForAuthorizer is used during OpenAPI document generation. An Authorizer that uses your validator will encode the returned security requirements into the OpenAPI operations being secured.
See also http://aqueduct.io/docs/auth/authorizer/#using-authorizers-without-authserver.
#override
FutureOr<Authorization> validate<T>(AuthorizationParser<T> parser, T authorizationData, {List<AuthScope> requiredScope}) {
final validUsername = 'bob';
final validPassword = 'password123';
final credentials = authorizationData as AuthBasicCredentials;
if (credentials.username == validUsername
&& credentials.password == validPassword) {
return Authorization(
null, // no client ID for basic auth
await getUserIDFromUsername(validUsername), // This is your problem to solve
this, // always this
credentials: credentials // if you want to pass this info along
);
}
return null;
}

Programatically authenticate AzureAd/OpenId to an MVC controller using C# and get redirect uri

I have overridden the built in WebClient as below. Then I call it
public class HttpWebClient : WebClient
{
private Uri _responseUri;
public Uri ResponseUri
{
get { return _responseUri; }
}
protected override WebResponse GetWebResponse(WebRequest request)
{
WebResponse response = base.GetWebResponse(request);
_responseUri = response.ResponseUri;
return response;
}
}
Then I consume it like this:
using (HttpWebClient client = new HttpWebClient())
{
client.Headers[HttpRequestHeader.Authorization] = $"Bearer { _token }";
client.Headers[HttpRequestHeader.ContentType] = "application/json";
client.UploadData(_url, Encoding.UTF8.GetBytes(_data));
string queryString = client.ResponseUri.Query.Split('=').Last();
}
The response uri comes back with "https://login.microsoftonline" rather than url returned from the MVC controller with a query string, as it is authenticating first with that bearer token using AzureAd/OpenId. If i call it twice it returns the original _url but not the redirected one. If I remove AzureAd authentication it works fine. Is there a way to force the response uri to come back as what the MVC controller sets it to?
Assuming you use the 'UseOpenIdConnectAuthentication' and configuring it to use AAD authentication, you can modify the redirect uri by setting Notifications.RedirectToIdentityProvider, something like:
Notifications = new OpenIdConnectAuthenticationNotifications
{
RedirectToIdentityProvider = async _ =>
{
_.ProtocolMessage.RedirectUri = _.Request.Uri.ToString();
}
}
If you use something else , or maybe I didn't understand your problem - please supply more information

Revoke JWT Oauth2 Refresh Token

I am trying to find a way to revoke Oauth2 JWT Refresh Token with vanilla Spring implementation and JwtTokenStore.
First: can somebody confirm that there is no API similar to /oauth/token that allows me to revoke a refresh token?
I wanted to add a custom API that would delete the refresh token along the folowing lines:
OAuth2RefreshToken oauth2RefreshToken=tokenStore.readRefreshToken(refreshToken);
tokenStore.removeRefreshToken(oauth2RefreshToken);
Now, looking at the JwtTokenStore, I noticed that it uses an ApprovalStore. So I went ahead and provided an InMemoryApprovalStore to my JwtTokenStore. My JwtTokenStore instantiation this look as follows:
#Bean
protected JwtAccessTokenConverter jwtTokenEnhancer() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("123456");
return converter;
}
#Bean
public JwtTokenStore getTokenStore(){
tokenStore= new JwtTokenStore(jwtTokenEnhancer());
tokenStore.setApprovalStore(new InMemoryApprovalStore());
tokenStore.setTokenEnhancer(jwtTokenEnhancer());
return tokenStore;
};
Results: with no InMemoryApprovalStore, I can authenticate users and refresh tokens without problems. However, as soon as I add InMemoryApprovalStore to the token store, I start getting the following error message:
{"error":"invalid_grant","error_description":"Invalid refresh token: eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE0NDUwMjQ2MTcsInVzZXJfbmFtZSI6IjYzZjIyYjZlLWU5MGUtNDFjYS1iYzJlLTBmZTgzNmY3MTQ2NyIsImF1dGhvcml0aWVzIjpbIlJPTEVfQURNSU4iLCJST0xFX1VTRVIiXSwianRpIjoiMjgwMDgwNWQtMjk1Zi00ZDQzLWI2NTYtMDNlZWYwMWFkMjg0IiwiY2xpZW50X2lkIjoid2ViLWNsaWVudCIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSIsInRydXN0Il19.BPC0HqLYjWGM0IFjvsUGGKQ9dyIXSXwMhraCVFIxD0U"}
My second question is thus what is the proper way to revoke a refresh token?
Edit: I found the following thread that suggests that ApprovalStore is indeed the way to revoke JWT tokens. I now just need to find out how to use them properly.
First: can somebody confirm that there is no API similar to /oauth/token that allows me to revoke a refresh token?
Confirmed.
You don't need to define JwtTokenStore bean, spring will create it for you using AuthorizationServerEndpointsConfigurer
private TokenStore tokenStore() {
if (tokenStore == null) {
if (accessTokenConverter() instanceof JwtAccessTokenConverter) {
this.tokenStore = new JwtTokenStore((JwtAccessTokenConverter) accessTokenConverter());
}
else {
this.tokenStore = new InMemoryTokenStore();
}
}
return this.tokenStore;
}
private ApprovalStore approvalStore() {
if (approvalStore == null && tokenStore() != null && !isApprovalStoreDisabled()) {
TokenApprovalStore tokenApprovalStore = new TokenApprovalStore();
tokenApprovalStore.setTokenStore(tokenStore());
this.approvalStore = tokenApprovalStore;
}
return this.approvalStore;
}
My second question is thus what is the proper way to revoke a refresh token?
revoke the approval for the token, this was used by JwtTokenStore
private void remove(String token) {
if (approvalStore != null) {
OAuth2Authentication auth = readAuthentication(token);
String clientId = auth.getOAuth2Request().getClientId();
Authentication user = auth.getUserAuthentication();
if (user != null) {
Collection<Approval> approvals = new ArrayList<Approval>();
for (String scope : auth.getOAuth2Request().getScope()) {
approvals.add(new Approval(user.getName(), clientId, scope, new Date(), ApprovalStatus.APPROVED));
}
approvalStore.revokeApprovals(approvals);
}
}
}

Authenticating users with auth token in query string with ASP.NET MVC

[This question relates to ASP.NET MVC4, and it is about best-practice approach - so please, don't suggest hacks.]
I want to authenticate users using an auth token sent in the request URL. It works similarly to a password reset token, except in this case it does not go to a reset page but instead grants access to some portion of the site. The idea is to send the URL with the auth token to a verified email address of the user. Users can click the link and perform some actions without typing their password.
Out-of-the-box, ASP.NET has the [Authorize] attribute and the SimpleMembershipProvider - these seem to work great, but they do some voodoo magic under the hood (like auto-generating database tables), so I don't know how to extend them to add this link-based auth token.
I don't expect an exact answer, but please do point me to the right direction.
Thanks!
Uf, broad question. But I will try at least to direct you to a right direction.
So first if suggest that you use Forms Authentication as a base, but you will have to customize using of it. And I presume that you do not want to use cookies for the authentication as this is native behaviour of the Forms Authentication.
The most important point you should consider to have it you custom query string token based authentication.
Create a login action and in this action you will authorize the user, if he have granted access you ask FormsAuthentication to create AuthCookie. For the further on you just take the httpCookie.Value as your auth token that you will carry in query string.
You need to implement the Application_BeginRequest in the Global.asax that will handle this query string tokens and translate it into the cookie. With this approach you can leverage all the ASP.NET Forms Authentication infrastructure.
This is quite high level picture w/o code. If you need more detail help I can also provide it to you.
You should just use a regular Action that accepts HttpGet.
Upon receiving the token, immediately invalid it so it can't be used again.
Also, only accept tokens that are within your pre-defined range of time period, like 24 or 72 hours.
Thank you Peter for idea.
If smb need to create JWT token authorization for old ASP.NET MVC5.I wrote small example. I don't serialize cookie to JWT. I create a JWT and after I am checking it in the BeginRequest. If everything is ok, I create a cookie and set it to the httpContext.Request. I used authentication mode="Forms" for application and it require cookies.
For create JWT token:
const string secret = "GQDstcKsx0NHjPOuXOYg5MbeJ1XT0uFiwDVvVBrk";
[AllowAnonymous]
[HttpPost]
public ActionResult LoginJWT(LoginViewModel model)
{
ActionResult response = null;
if (ModelState.IsValid)
{
if (true) //todo: check user login&password
{
var payload = new Dictionary<string, object>
{
{ "iss", "subject" },
{ "sub", "api" },
{ "exp", DateTimeOffset.UtcNow.AddHours(2).ToUnixTimeSeconds()},
{ "iat", DateTimeOffset.UtcNow.ToUnixTimeSeconds()},
{ "jti", Guid.NewGuid() },
{ "uid", "64" } //custom field for identificate user
};
IJwtAlgorithm algorithm = new HMACSHA256Algorithm(); // symmetric
IJsonSerializer serializer = new JsonNetSerializer();
IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
var token = encoder.Encode(payload, secret);
response = Content(token);
}
else
{
response = new HttpStatusCodeResult(System.Net.HttpStatusCode.BadRequest, "Login or password are not found");
}
}
else
{
response = new HttpStatusCodeResult(System.Net.HttpStatusCode.BadRequest, "Errors in Model");
}
return response;
}
For check JWT token in Global.asax:
public override void Init()
{
this.BeginRequest += this.BeginRequestHandler;
base.Init();
}
private void BeginRequestHandler(object sender, EventArgs e)
{
var bearerToken = this.Context.Request.Headers["Authorization"];
if (bearerToken != null)
{
var token = bearerToken.StartsWith("Bearer ") ? bearerToken.Substring(7) : bearerToken;
const string secret = "GQDstcKsx0NHjPOuXOYg5MbeJ1XT0uFiwDVvVBrk";
int userId = 0;
try
{
IJsonSerializer serializer = new JsonNetSerializer();
var provider = new UtcDateTimeProvider();
IJwtValidator validator = new JwtValidator(serializer, provider);
IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
IJwtAlgorithm algorithm = new HMACSHA256Algorithm(); // symmetric
IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder, algorithm);
var json = decoder.DecodeToObject<IDictionary<string, string>>(token, secret, verify: true);
if (json.TryGetValue("uid", out var uid))
{
userId = Convert.ToInt32(uid);
}
}
catch (TokenExpiredException)
{
Console.WriteLine("Token has expired");
}
catch (SignatureVerificationException)
{
Console.WriteLine("Token has invalid signature");
}
if (userId != 0)
{
// check user by id, if found create cookie.
}
}
}
I used:
jwt-dotnet/jwt library 7.2.1

Post to Twitter from MVC

I saw couple of libraries which we can use to post to twitter. But I want to create my own as later we need to extend this for other social networks also .
I am using the RESTSharp to make things little easy for me.
In my controller, I wrote 2 methods..
public ActionResult TwitterLogin()
{
var authorizeUrl = TwitterService.Authorize();
if(!String.IsNullOrEmpty(authorizeUrl))
{
return Redirect(authorizeUrl);
}
else
{
return View();
}
}
public ActionResult AuthorizeCallback()
{
TwitterService.AuthorizeCallback();
return View();
}
In Twitter Service
public string Authorize()
{
client = new RestClient(BaseUrl) {Authenticator = OAuth1Authenticator.ForRequestToken(ConsumerKey, ConsumerSecret, CallbackUrl)};
var request = new RestRequest("oauth/request_token", Method.POST);
var response = client.Execute(request);
if(response.StatusCode == HttpStatusCode.OK)
{
var qs = HttpUtility.ParseQueryString(response.Content);
oauth_token = qs["oauth_token"];
oauth_token_secret = qs["oauth_token_secret"];
request = new RestRequest("oauth/authorize");
request.AddParameter("oauth_token", oauth_token);
return client.BuildUri(request).ToString();
}
return String.Empty;
}
public void AuthorizeCallback()
{
var verifier = "123456"; // <-- Breakpoint here (set verifier in debugger)
var request = new RestRequest("oauth/access_token", Method.POST);
client.Authenticator = OAuth1Authenticator.ForAccessToken(ConsumerKey, ConsumerSecret, oauth_token, oauth_token_secret, verifier);
var response = client.Execute(request);
var qs = HttpUtility.ParseQueryString(response.Content);
oauth_token = qs["oauth_token"];
oauth_token_secret = qs["oauth_token_secret"];
}
Now my concern is
Whether i am doing it right ?
Regarding Oauth, from what I understood , we create a request token from the twitter, ask the user to authorize it and use it to get an accesss Token and use it for signing other requests. I wrote this code primarly looking this link
https://github.com/restsharp/RestSharp/blob/master/RestSharp.IntegrationTests/oAuth1Tests.cs
Whether we can write this any better ?
Also somebody could guide me on this , how to use the RestSharp to create OAuth requests to use the API's like twitter. Most of the internet references are based on the custom libs

Resources