how to extract jwk from identityServer4 in java spring - spring

I am currently using library jwks-rsa. I want to extract the public key from identityServer4.
DecodedJWT jwt = JWT.decode(token);
try {
URL url = new URL("https://localhost:31300/.well-known/openid-configuration/jwks");
JwkProvider provider = new UrlJwkProvider(url);
Jwk jwk = null;
String kid = jwt.getKeyId();
jwk = provider.get(kid);
Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) jwk.getPublicKey(), null);
algorithm.verify(jwt);
} catch (JwkException | MalformedURLException e) {
e.printStackTrace();
}
I am getting error at jwk=provider.get(kid). The exception is com.auth0.jwk.SigningKeyNotFoundException: Cannot obtain jwks from url https://localhost:31300/.well-known/openid-configuration/jwks However, I can access it through postman
{
"keys": [
{
"kty": "RSA",
"use": "sig",
"kid": "0538f4763b647a8a01305774b9f4d5f1",
"e": "AQAB",
"n": "6h5hL5UfOW8SGFRNeVuU9M92p6cOWF-941vGqZ8y-PL6jC-B_2S7kp_Cw7SvOajd6CqBpQyiuP21pjhQILU4ikqq7-WbnxNZcvOQcYPLpUzupn5MBQkHk_bYONPInu-jU55FZhuYdO3sz0qS58AEqlnQbKZYLvU_KS_Ou4mSnTJr_hfwrk75cnsAMzhkVcsMt9GaSJZbj4zccIEUVQpiYLTY3gK_Nbym5ZKYfsayOHDSwLLsZchJ5VJnc1mAiZwGtszyjdCJSipQF_wdFcacmfGDwyXY4mnER32aT5Fo20lihnEJ5T1IXkwFMgWJVesiaHJQNqxAMEg86SWSN3_A0Q",
"alg": "RS256"
}
]
}

The URL should be the url to IdentityServer, like this https://localhost:31300. Not the full path to the JWKS document itself.

Related

send the ios push notification during the Expired Provider Token error showed

I am trying to develop an mobile application using asp.net web api and xamarin forms. Getting errors in web api Project:ExpiredProviderToken
I am facing problem to the send the push notification in ios using Apns service.
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
{
var notificationSettings = UIUserNotificationSettings.GetSettingsForTypes(
UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound, null
);
UIApplication.SharedApplication.RegisterUserNotificationSettings(notificationSettings);
UIApplication.SharedApplication.RegisterForRemoteNotifications();
}
else
{
UIRemoteNotificationType notificationTypes = UIRemoteNotificationType.Alert | UIRemoteNotificationType.Badge | UIRemoteNotificationType.Sound;
UIApplication.SharedApplication.RegisterForRemoteNotificationTypes(notificationTypes);
}
global::Xamarin.Forms.Forms.SetFlags("CollectionView_Experimental");
global::Xamarin.Forms.Forms.Init();
LoadApplication(new App());
return base.FinishedLaunching(app, options);
}
public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
var IosDeviceToken = UIDevice.CurrentDevice.IdentifierForVendor.ToString();
if (!string.IsNullOrWhiteSpace(IosDeviceToken))
{
IosDeviceToken = IosDeviceToken.Trim('<').Trim('>');
var model = new IosDevice { IosDeviceId = IosDeviceToken };
string url = "http://notificationdemo.project-demo.info:8075/DeviceToken/Addtoken";
HttpClient client = new HttpClient();
string jsonData = JsonConvert.SerializeObject(model);
StringContent content = new StringContent(jsonData, Encoding.UTF8, "application/json");
var response = client.PostAsync(url, content);
var result = response.Result.StatusCode;
}
}
public override void FailedToRegisterForRemoteNotifications(UIApplication application, NSError error)
{
var model = new IosDevice { IosDeviceId = error.LocalizedDescription };
string url = "http://notificationdemo.project-demo.info:8075/DeviceToken/Addtoken";
HttpClient client = new HttpClient();
string jsonData = JsonConvert.SerializeObject(model);
StringContent content = new StringContent(jsonData, Encoding.UTF8, "application/json");
var response = client.PostAsync(url, content);
var result = response.Result.StatusCode;
//new UIAlertView("Error registering push notifications", error.LocalizedDescription, null, "OK", null).Show();
}
}
Below code is web api project
public void SendIOSNotification()
{
var options = new ApnsJwtOptions()
{
BundleId = "com.itpathsolutions.xamarin",
CertFilePath = #"D:\XamarinForms\demoapp\demoapp\demoapp.iOS\AuthKey_B95M9X635C.p8",
KeyId = "B95M9X635C",
TeamId = "M36758127B"
};
var apns = ApnsClient.CreateUsingJwt(new HttpClient(new WinHttpHandler()), options);
var push = new ApplePush(ApplePushType.Alert)
.AddBadge(1)
.AddSound("sound.caf")
.AddCustomProperty("category", "", true)
.AddCustomProperty("alert", "Good Morning iOS", true)
.AddCustomProperty("Id", "47474", true)
.AddCustomProperty("CreatedDate", DateTime.Now.ToString(), true)
.AddCustomProperty("url", "www.google.com", true)
.AddCustomProperty("content-available", "1", true)
.AddToken("CE227D98-4D25-43A6-AEF0-870DB1028772");
try
{
var response = apns.SendAsync(push).Result;
if (response.IsSuccessful)
{
Console.WriteLine("An alert push has been successfully sent!");
}
else
{
switch (response.Reason)
{
case ApnsResponseReason.BadCertificateEnvironment:
break;
// TODO: process other reasons we might be interested in
default:
throw new ArgumentOutOfRangeException(nameof(response.Reason), response.Reason, null);
}
Console.WriteLine("Failed to send a push, APNs reported an error: " + response.ReasonString);
}
}
catch (TaskCanceledException)
{
Console.WriteLine("Failed to send a push: HTTP request timed out.");
throw;
}
catch (HttpRequestException ex)
{
Console.WriteLine("Failed to send a push. HTTP request failed: " + ex);
throw;
}
}
The problem is related to server side .
Check the apple docs .
For security, APNs requires you to refresh your token regularly. Refresh your token no more than once every 20 minutes and no less than once every 60 minutes. APNs rejects any request whose token contains a timestamp that is more than one hour old. Similarly, APNs reports an error if you recreate your tokens more than once every 20 minutes.
On your provider server, set up a recurring task to recreate your token with a current timestamp. Encrypt the token again and attach it to subsequent notification requests.
The docs clear indicates that On your provider server, set up a recurring task to recreate your token with a current timestamp. Encrypt the token again and attach it to subsequent notification requests.
Also check the similar thread : iOS sending push with APNs Auth Key: suddenly "403 Forbidden: {"reason":"InvalidProviderToken"}" .

Update inner object element in Json using Gson

I have below json and need to update elements, below code works for elements in top level, How can I extend this to work it inside another inner level (object).
Json:
{
"name": George,
"version": "2.0",
"reqParams": {
"headerId": "this needs to be updated",
"queue": "draft",
}
}
In below code I am passing below
eg.
keyPath = "headerId"
updateText = "123456"
jsonText = above json
Code :
public String updateValue(String keyPath, String updateText, String jsonText) {
String[] keys = keyPath.split("/");
JsonParser jsonParser = new JsonParser();
JsonObject jsonObject = (JsonObject) jsonParser.parse(jsonText);
JsonObject returnVal = jsonObject; // This holds the ref to target json object
JsonPrimitive jp = new JsonPrimitive(updateText);
String finalKey = keys[keys.length - 1];
for(String key : keys)
{
if (jsonObject.get(key) != null && jsonObject.get(key).isJsonObject())
{
jsonObject = (JsonObject)jsonObject.get(key);
}
}
jsonObject.remove(finalKey);
jsonObject.add(finalKey, jp);
return returnVal.toString();
}
Code
Expected out put json:
{
"name": George,
"version": "2.0",
"reqParams": {
"headerId": "123456",
"queue": "draft",
}
}
Actual reult:
{
"name": George,
"version": "2.0",
"reqParams": {
"headerId": "this needs to be updated",
"queue": "draft",
},
"headerId": "123456",
}
Pass keyPath as "reqParams/headerId" because headerId is inside reqParams and not at root level of JSON.
Updated code slightly and pass parameters as suggested by #Smile answer
keyPath : reqParams/headerId
someId (if exist in root level)
Code :
public String updateValue(String keyPath, String updateText, String jsonText) {
String[] keys = keyPath.split("/");
JsonParser jsonParser = new JsonParser();
JsonObject jsonObject = (JsonObject) jsonParser.parse(jsonText);
JsonObject returnVal = jsonObject; // This holds the ref to target json object
JsonPrimitive jp = new JsonPrimitive(updateText);
String finalKey = keys[keys.length - 1];
for (String key : keys) {
if (jsonObject.get(key) != null && jsonObject.get(key).isJsonObject()) {
jsonObject = (JsonObject) jsonObject.get(key);
jsonObject.remove(finalKey);
jsonObject.add(finalKey, jp);
return returnVal.toString();
} else if (jsonObject.get(finalKey) == null) {
return returnVal.toString();
}
}
jsonObject.remove(finalKey);
jsonObject.add(finalKey, jp);
return returnVal.toString();
}

Invalid state from server. Possible forgery! error in Xamarin.Auth

Why I get this error message when trying to use the Xamarin.Auth Api?
I am running on Android Plataform and using Xamarin.Forms
OAuth2Authenticator auth = new OAuth2Authenticator
(
clientId: AppKeyDropboxtoken,
scope: "",
authorizeUrl: new Uri("https://www.dropbox.com/oauth2/authorize"),
redirectUrl: new Uri(RedirectUri),
isUsingNativeUI: false
);
auth.Completed += (sender, eventArgs) =>
{
if (eventArgs.IsAuthenticated)
{
// Use eventArgs.Account to do wonderful things
this.AccessToken = eventArgs.Account.Properties["access_token"].ToString();
Debug.WriteLine("AccessToken: " + this.AccessToken);
openDropboxFileList();
}
};
var presenter = new Xamarin.Auth.Presenters.OAuthLoginPresenter();
presenter.Login(auth);
Create a class and add this code below:
public class AuthenticatorExtensions : OAuth2Authenticator
{
public AuthenticatorExtensions(string clientId, string clientSecret, string scope, Uri authorizeUrl, Uri redirectUrl, Uri accessTokenUrl, GetUsernameAsyncFunc getUsernameAsync = null, bool isUsingNativeUI = false) : base(clientId, clientSecret, scope, authorizeUrl, redirectUrl, accessTokenUrl, getUsernameAsync, isUsingNativeUI)
{
}
protected override void OnPageEncountered(Uri url, System.Collections.Generic.IDictionary<string, string> query, System.Collections.Generic.IDictionary<string, string> fragment)
{
// Remove state from dictionaries.
// We are ignoring request state forgery status
// as we're hitting an ASP.NET service which forwards
// to a third-party OAuth service itself
if (query.ContainsKey("state"))
{
query.Remove("state");
}
if (fragment.ContainsKey("state"))
{
fragment.Remove("state");
}
base.OnPageEncountered(url, query, fragment);
}
}
Then use it as below:
[Obsolete]
private void SignInGoogleAuth()
{
try
{
string clientId = null;
string redirectUri = null;
//Xamarin.Auth.CustomTabsConfiguration.CustomTabsClosingMessage = null;
clientId = Constants.GoogleAndroidClientId;
redirectUri = Constants.GoogleAndroidRedirectUrl;
account = store.FindAccountsForService(Constants.AppName).FirstOrDefault();
var authenticator = new AuthenticatorExtensions(
clientId,
null,
Constants.GoogleScope,
new Uri(Constants.GoogleAuthorizeUrl),
new Uri(redirectUri),
new Uri(Constants.GoogleAccessTokenUrl),
null,
true);
authenticator.Completed += OnAuthCompleted;
authenticator.Error += OnAuthError;
AuthenticationState.Authenticator = authenticator;
var presenter = new Xamarin.Auth.Presenters.OAuthLoginPresenter();
presenter.Login(authenticator);
}
catch (Exception ex)
{
ShowAlert("Alert", ex.Message);
}
}
[Obsolete]
async void OnAuthCompleted(object sender, AuthenticatorCompletedEventArgs e)
{
var authenticator = sender as OAuth2Authenticator;
if (authenticator != null)
{
authenticator.Completed -= OnAuthCompleted;
authenticator.Error -= OnAuthError;
}
if (e.IsAuthenticated)
{
// If the user is authenticated, request their basic user data from Google
// UserInfoUrl = https://www.googleapis.com/oauth2/v2/userinfo
var request = new OAuth2Request("GET", new Uri(Constants.GoogleUserInfoUrl), null, e.Account);
var response = await request.GetResponseAsync();
if (response != null)
{
// Deserialize the data and store it in the account store
// The users email address will be used to identify data in SimpleDB
string userJson = await response.GetResponseTextAsync();
StaticVariables.googleProfile = JsonConvert.DeserializeObject<GoogleProfile>(userJson);
}
if (account != null)
{
store.Delete(account, Constants.AppName);
}
await store.SaveAsync(account = e.Account, Constants.AppName);
Application.Current.Properties.Remove("Id");
Application.Current.Properties.Remove("FirstName");
Application.Current.Properties.Remove("LastName");
Application.Current.Properties.Remove("DisplayName");
Application.Current.Properties.Remove("EmailAddress");
Application.Current.Properties.Remove("ProfilePicture");
Application.Current.Properties.Add("Id", StaticVariables.googleProfile.Id);
Application.Current.Properties.Add("FirstName", StaticVariables.googleProfile.GivenName);
Application.Current.Properties.Add("LastName", StaticVariables.googleProfile.FamilyName);
Application.Current.Properties.Add("DisplayName", StaticVariables.googleProfile.Name);
Application.Current.Properties.Add("EmailAddress", StaticVariables.googleProfile.Email);
Application.Current.Properties.Add("ProfilePicture", StaticVariables.googleProfile.Picture);
await Navigation.PushAsync(new GoogleProfilePage());
}
}
[Obsolete]
void OnAuthError(object sender, AuthenticatorErrorEventArgs e)
{
var authenticator = sender as OAuth2Authenticator;
if (authenticator != null)
{
authenticator.Completed -= OnAuthCompleted;
authenticator.Error -= OnAuthError;
}
Debug.WriteLine("Authentication error: " + e.Message);
}
I was getting the infamous "Possible Forgery!" error and overrode OnPageEncountered() to work around it as many have done. This turns out to be unnecessary as well as insecure.
Oauth2Authenticator is stateful so you will get this problem if you don't use the same instance of OAuth2Authenticator to invoke OnPageLoading() as was used to initiate the authentication.
To resolve, just save the instance of OAuth2Authenticator used for initiating authentication and then reuse it when calling OnPageLoading() in your OauthInterceptor.

Google Drive Authorized Code While Redirect URL WEBAPI

I am using Below Code to access Drive API, for that I am using WEBAPI not MVC Web Application.
var flow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = new ClientSecrets
{
ClientId = "XXXXX",
ClientSecret = "XXXXX"
},
Scopes = new[] { DriveService.Scope.Drive }
});
// var result = new AuthorizationCodeWebApp(flow, "http://localhost:1344/api/AuthCallback/IndexAsync", "");
var result = new AuthorizationCodeWebApp(flow, "http://localhost:1344/api/GoogleImport/Listfile", "");
var resultData = result.AuthorizeAsync("user",CancellationToken.None).Result;
if (result1.Credential != null)
{
var service123 = new DriveService(new BaseClientService.Initializer
{
HttpClientInitializer = resultData.Credential,
ApplicationName = "ASP.NET MVC Sample",
});
var list = await service123.Files.List().ExecuteAsync();
}
else
{
System.Web.HttpContext.Current.Response.Redirect(resultData.RedirectUri);
}
In webapi it's hard to Response.Redirect so how can I manage once authorized code result. Credential not populated?
Is there any other way to authorize code?
Here is the documentation to help you in your questions.
OAuth 2.0
This document describes OAuth 2.0, when to use it, how to acquire
client IDs, and how to use it with the Google API Client Library for
.NET.
OAuth 2.0 Protocol
OAuth 2.0 is the authorization protocol used by Google APIs. You
should get familiar with the protocol by reading the following links:
The OAuth 2.0 Authorization Protocol
Using OAuth 2.0 to Access Google APIs
There is also a provided sample code on how the OAuth 2.0 was implemented. Try to check it. You can do the same on your code.
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Books.v1;
using Google.Apis.Books.v1.Data;
using Google.Apis.Services;
using Google.Apis.Util.Store;
namespace Books.ListMyLibrary
{
/// <summary>
/// Sample which demonstrates how to use the Books API.
/// https://developers.google.com/books/docs/v1/getting_started
/// <summary>
internal class Program
{
[STAThread]
static void Main(string[] args)
{
Console.WriteLine("Books API Sample: List MyLibrary");
Console.WriteLine("================================");
try
{
new Program().Run().Wait();
}
catch (AggregateException ex)
{
foreach (var e in ex.InnerExceptions)
{
Console.WriteLine("ERROR: " + e.Message);
}
}
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
}
private async Task Run()
{
UserCredential credential;
using (var stream = new FileStream("client_secrets.json", FileMode.Open, FileAccess.Read))
{
credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
new[] { BooksService.Scope.Books },
"user", CancellationToken.None, new FileDataStore("Books.ListMyLibrary"));
}
// Create the service.
var service = new BooksService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Books API Sample",
});
var bookshelves = await service.Mylibrary.Bookshelves.List().ExecuteAsync();
...
}
}
}

How to disable Subject Key Identifier in SecurityTokenResolver

I am processing a SAML2 token in WIF which contains an EncryptedAssertion. The mark-up does NOT contain a "Subject Identifier Key" Extension property and as such WIF SecurityTokenHandler fails as it tries to get the correct X509 certificate from the LocalMachineStore/Personal.
The issue is clearly that the certificate used to encrypt the token does not contain the SKI Extension and of course the token generation code (Java) does not do seem to require it. To avoid having to modify the generation code is there a way I can get WIF SecuityTokenResolver to NOT check the received Token for the SKI but simply use the local store certificate directly to decrypt the token?
In the end I just implemented a custom SecurityTokenResolver and implemented the TryResolveSecurityKeyCore method.
Here is the code:
public class mySaml2SSOSecurityTokenResolver : SecurityTokenResolver
{
List<SecurityToken> _tokens;
public PortalSSOSecurityTokenResolver(List<SecurityToken> tokens)
{
_tokens = tokens;
}
protected override bool TryResolveSecurityKeyCore(System.IdentityModel.Tokens.SecurityKeyIdentifierClause keyIdentifierClause, out System.IdentityModel.Tokens.SecurityKey key)
{
var token = _tokens[0] as X509SecurityToken;
var myCert = token.Certificate;
key = null;
try
{
var ekec = keyIdentifierClause as EncryptedKeyIdentifierClause;
if (ekec != null)
{
switch (ekec.EncryptionMethod)
{
case "http://www.w3.org/2001/04/xmlenc#rsa-1_5":
{
var encKey = ekec.GetEncryptedKey();
var rsa = myCert.PrivateKey as RSACryptoServiceProvider;
var decKey = rsa.Decrypt(encKey, false);
key = new InMemorySymmetricSecurityKey(decKey);
return true;
}
}
var data = ekec.GetEncryptedKey();
var id = ekec.EncryptingKeyIdentifier;
}
}
catch (Exception ex)
{
// Do something here }
return true;
}
protected override bool TryResolveTokenCore(System.IdentityModel.Tokens.SecurityKeyIdentifierClause keyIdentifierClause, out System.IdentityModel.Tokens.SecurityToken token)
{
throw new NotImplementedException();
}
protected override bool TryResolveTokenCore(System.IdentityModel.Tokens.SecurityKeyIdentifier keyIdentifier, out System.IdentityModel.Tokens.SecurityToken token)
{
throw new NotImplementedException();
}
}
}

Resources