How to connect azure Ad with java web application using certificate? - spring-boot

I have to connect azure ad to my java web application with certificate and without client Secret.
any idea how to do this.
Really appreciate the replies .

Take a look to the If you have a certificate section in Instantiating a Confidential Client application:
String PUBLIC_CLIENT_ID;
String AUTHORITY;
PrivateKey PRIVATE_KEY;
X509Certificate PUBLIC_KEY;
IClientCredential credential = ClientCredentialFactory.createFromCertificate(PRIVATE_KEY, PUBLIC_KEY);
ConfidentialClientApplication app =
ConfidentialClientApplication
.builder(PUBLIC_CLIENT_ID, credential)
.authority(AUTHORITY)
.build();
Also, to Client Credentials with certificate.

Related

REST stages should be configured to use SSL certificates for backend authentication

I'm trying to pass a security compliance check under AWS Security Hub - [APIGateway.2] API Gateway REST API stages should be configured to use SSL certificates for backend authentication.
What have I done?
created a Client Certificate from AWS API Gateway
selected an API and attached generated Client Certificate to a stage
copied generated Client Certificate's key into secrets/apig-cert.pem of backend
updated index service as below
const nestApplicationOptions: NestApplicationOptions = {
httpsOptions: {
ca: [fs.readFileSync('secrets/apig-cert.pem')],
requestCert: true,
rejectUnauthorized: true,
},
};
const expressApp = express();
const adapter = new ExpressAdapter(expressApp);
const app = await NestFactory.create<NestExpressApplication>(
AppModule,
adapter,
nestApplicationOptions,
);
...
await app.init();
await awsServerlessExpress.createServer(expressApp);
Expected behaviour:
Under Security Hub, corresponding compliance status check should pass
If client certificate is detached from API stage under API Gateway, lambda service should throw invalid certificate error
Current behaviour:
Combining step 1 and 2 together resolved the compliance status check
API works in all cases, even if the certificate is detached from the API stage under the API Gateway
I'm not sure what is missing here. Something I believe is fishy with how I'm using NestFactory.create or awsServerlessExpress.createServer.
Extra info:
API mapping is done to the same stage from API Gateway > Custom domain names
Reference links-
fsbp-apigateway-2
Getting started with client side SSL authentication
#kartoon if you pay attention to the documentation it says
Before configuring a backend HTTPS server to verify the client SSL certificate of API Gateway, you must have obtained the PEM-encoded private key and a server-side certificate that is provided by a trusted certificate authority.
Your server side code should have the private key configured with a cert that if will present to API gateway.
If you look at the sample express code provided in the AWS documentation, below are the two lines I am talking about.
key: fs.readFileSync('server-key.pem'),
cert: fs.readFileSync('server-cert.pem'),
Your code in that case should look like
const nestApplicationOptions: NestApplicationOptions = {
httpsOptions: {
ca: [fs.readFileSync('CA-SIGNER-CERT.pem')],
cert: [fs.readFileSync('PUBLIC-CERT.pem')],
key: [fs.readFileSync('PRIVATE-KEY.key')],
requestCert: true,
rejectUnauthorized: true,
},
};

How do I find my server's public key info to do certificate pinning in OkHttp?

I have a server with a custom certificate on it issued by my own personal certificate authority. It's not on a public domain so it's not possible to use a standard certificate authority. I want to get an Android client to connect to this server using OkHttp. According to the docs, the code should look like this:
CertificatePinner certificatePinner = new CertificatePinner.Builder()
.add("myserver.com", "sha256/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=")
.build();
Where the SHA256 hash is, quoting the docs: "a hash of a certificate’s Subject Public Key Info, base64-encoded and prefixed with either sha256/ or sha1/". I have the cert and the key files for the server, but how can I get the required hash?
I'm using OkHttp 3.
Try making a request to your server with the configuration above to see how that fails. The exception should tell you which pins were found.
You must do certificate pinning in coordination with your server team! Otherwise a change they make will prevent your client from being able to reach the server.

How to disable credentials input for HTTPS call to my WCF hosted in windows service

I'm just creating my first WCF project, so I have a lot of deficiencies in knowledge in this field. My problem is that when I'm calling my WCF url in web browser, I have to enter the credentials but I cannot even use my domain name and password, but I have to choose my personal chip card certificate and enter it's password. After that, everything work like a charm.
My final product should be installed on every user workstation in our domain for IT operations purposes only. So there will be some AD authorization after that.
About certificate... We have our own company root CA certificate, and every workstation have it's own certificate which is it's grandchild:
Example of our certificate tree:
COMPANYROOTCA >> COMPANYSUBCA1 >> WORKSTATIONNAME.DOMAIN (this one is used as WCF service cert)
This is what I have right now for hosting the WCF in my Windows service running under NetworkService Account:
serviceHost.Dispose(); //extension for close() and set to null
Uri httpsUrl = new Uri("baseAdress");
serviceHost = new ServiceHost(typeof(Service.myService), httpsUrl);
WSHttpBinding wsHttpBinding = new WSHttpBinding();
wsHttpBinding.Security.Mode = SecurityMode.Transport;
wsHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
wsHttpBinding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
WebHttpBinding webHttpBinding = new WebHttpBinding();
webHttpBinding.Security.Mode = WebHttpSecurityMode.Transport;
webHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
webHttpBinding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
ServiceMetadataBehavior smb = new ServiceMetadataBehavior
{
HttpGetEnabled = false,
HttpsGetEnabled = true,
};
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection collection = store.Certificates;
X509Certificate2 cert = collection.OfType<X509Certificate2>().First(c => c.SubjectName.Name == "CN=WorkstationName.Domain");
store.Close();
serviceHost.Credentials.ServiceCertificate.Certificate = cert;
ServiceThrottlingBehavior throttleBehavior = new ServiceThrottlingBehavior
{
MaxConcurrentCalls = 16,
MaxConcurrentInstances = 26,
MaxConcurrentSessions = 10
};
serviceHost.Description.Behaviors.Add(throttleBehavior);
ServiceEndpoint soapEndpoint = serviceHost.AddServiceEndpoint(typeof(Contract.IMyService), wsHttpBinding, "soap");
ServiceEndpoint restEndpoint = serviceHost.AddServiceEndpoint(typeof(Contract.IMyService), webHttpBinding, "rest");
ServiceEndpoint mexEndpoint = serviceHost.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpsBinding(), "mex");
restEndpoint.Behaviors.Add(new WebHttpBehavior());
tempAdminHost.Open();
So my question is: Is there any way, how to, for example, automaticaly get domain account which use the browser and call the url or any alternative how to still use HTTPS but without putting any credentials?
I didn’t see the way you use the credential to authenticate the client. the client credential type of the two endpoints you use to host the service are None. How does the browser ask you to input the credential? Besides, by default, If the server set up the ClientCredentialType to Windows, the client would use the current user as the credential. The current user’s password and account will be default credential when need to provide a credential.
One more thing to note, if you are simply prompted in the browser to select a certificate instead of the credential(user/password), as follows,
We may have configured the following parameter(clientcertnegotiation parameter).
netsh http add sslcert ipport=127.0.0.1:8000 certhash=c20ed305ea705cc4e36b317af6ce35dc03cfb83d appid={c9670020-5288-47ea-70b3-5a13da258012} clientcertnegotiation=enable
Because the way you use to provide a certificate to encrypt the communication is not correct.
serviceHost.Credentials.ServiceCertificate.Certificate = cert;
We need to bind the certificate to Port.
https://learn.microsoft.com/en-us/windows/desktop/http/add-sslcert
when hosting the service in IIS, we accomplish it by the below UI.
And the parameter configuration depends on the below.
So I suspect the process that binds the certificate to the specified port is completed by IIS. and the parameter should be ignored.
Feel free to let me know if there is anything I can help with.

Identity Server - HTTPS binding, SAN Certificate & NLB

I need help regarding Identity Server on the following:
Do reference tokens use Signing Certificate?
On http://localhost application is working fine, on binding to a public URL with https, the login call returns a token, but consecutive WebApi(client) calls return "401 - Authorization has been denied for this request". Is it because of SSL certificate or due to NLB (two different Identity servers are deployed on the backend) - I am using Entity framework for storing the reference tokens. Do multi domain SSL certificate (SAN) work fine for Identity Server?
Do I need to add machine keys on both Identity server config files to sync or is this requirement only for JWT approach?
Thanks.

How to access Google API in combination with Azure AD single-sign on

I have a web application running on Azure. The web application authenticates the users via OpenID Connect from a Azure Active Directory tenant.
Azure Sample on GitHub.
On the Azure Active Directory tenant I have integrated Google Apps and configured single sing-on to Google Apps and automated user provisioning. Tutorial: How to integrate Google Apps with Azure Active Directory.
In my web application I would like to access user content from Google Apps (e.g. files on Google Drive) of the signed in user via Google API.
Is it possible to do this with the help of the setup single sign-on federation, so that the user only needs to sign in to the web application/Azure AD and for the Web API call there is no need for a further sign in, e.g. by using a token optained by Azure AD for accessing the Google Web API?
Tokens obtained from Azure AD cannot be used directly against Google API. However if you integrated Azure AD and Google Apps you should be able to go through the google token acquisition process without gathering user credentials again. You might want to go through an authorization code flow for getting tokens from google, and inject in the request information that would help to leverage your existing session. Typical examples are passing your user's UPN (via login_hint query parameter) and tenant (domain_hint). However I don't know if the google authorization endpoint will pass those along, you'll need to consult the google api documentation.
I ended up with two solutions:
a) Service Account:
Accessing the users data with a service account on behalf of a user.
For this you have to setup a service account: Using OAuth 2.0 for Server to Server Applications
private static ServiceAccountCredential GetServiceAccountCredential(string user)
{
const string privateKey = "<PRIVATEKEY>";
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer("<SERVICEACOUNTEMAIL>")
{
Scopes = new[] {DriveService.Scope.Drive},
User = user
}.FromPrivateKey(privateKey));
return credential;
}
b) User:
Accessing the users data with the user. For this you have to register your app to get the client ID and secret: Using OAuth 2.0 for Web Server Applications
private static UserCredential GetUserCredential(string user)
{
ClientSecrets secrets = new ClientSecrets
{
ClientId = "<CLIENTID>",
ClientSecret = "<CLIENTSECRET>"
};
IDataStore credentialPersistanceStore = new FileDataStore("Drive.Sample.Credentials");
Task<UserCredential> result = GoogleWebAuthorizationBroker.AuthorizeAsync(
secrets,
new[] {DriveService.Scope.Drive},
user,
CancellationToken.None,
credentialPersistanceStore);
result.Wait();
UserCredential credential = result.Result;
return credential;
}
With the credentials I can request the files from Drive:
Claim emailClaim = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Email);
IConfigurableHttpClientInitializer credential = GetServiceAccountCredential(emailClaim.Value);
//IConfigurableHttpClientInitializer credential = GetUserCredential(emailClaim.Value);
var service = new DriveService(new BaseClientService.Initializer
{
HttpClientInitializer = credential,
ApplicationName = "My App"
});
FileList list = service.Files.List().Execute();
I am not yet sure which option I will use. Maybe you have some advices or suggestions.

Resources