Session & Token Fixation in IBM MobileFirst Platform 7.1 - security

We're developing a hybrid app, cordova based using MFP 7.1 It was observed that the app uses client ID as session ID. As follow in the red box
It was found that the Client ID will not be changed until reinstallation of the application. Whenever a user login on the device, its identity will be associated with the Client ID. With the Client ID, it may be able to retrieve another ID WL-Instance-ID from the application server. With valid Client ID and WL-Instance-ID, attacker will be able to access the application with the privilege of the victim user.
How to dissociate Client ID and Session ID? i.e. it should not be possible to retrieve a valid Session ID/token just by Client ID. And Session ID/token should be changed during change in security context.
We follow the instructions from here to implement the authentication
https://mobilefirstplatform.ibmcloud.com/tutorials/en/foundation/7.1/authentication-security/custom-authentication/
Create mobileSecurityTest to protect adapter’s procedures; it's in SecurityTests section.
<mobileSecurityTest name="LoginAdapter-securityTest">
<testUser realm="LoginAdapterRealm" />
<testDeviceId provisioningType="none" />
<testDirectUpdate mode="disabled"/>
</mobileSecurityTest>
Use AdapterAuthenticator to handle userIdentity, and define two methods LoginAdapter.onAuthRequired, LoginAdapter.onLogout in LoginAdapter to handle security request.
<realm loginModule="LoginAdapterModule" name="LoginAdapterRealm">
<className>com.worklight.integration.auth.AdapterAuthenticator</className>
<parameter name="login-function" value="LoginAdapter.onAuthRequired" />
<parameter name="logout-function" value="LoginAdapter.onLogout" />
</realm>
Define module to create and store user identities that is used by LoginAdapterRealm; it's in loginModules section.
<loginModule name="LoginAdapterModule" expirationInSeconds="1800">
<className>com.worklight.core.auth.ext.NonValidatingLoginModule</className>
</loginModule>

Related

Can not connect to Azure SQL Server using Active directory integrated authentication in AppService

We have web application deploy on Azure App Service. Our database is also on Azure which is configured to use AAD authentication (We have assigned AAD Admin).
We are using below connection string in web app to connect to this server and database using below connections string.
Data Source=xxxxxxx.database.windows.net;Initial
Catalog=xxxxxxx;Persist Security Info=False;Authentication=Active
Directory Integrated
Please note: This connection string is working fine when using thru local system. But getting below error when we use this conn string in Azure App Service:
Failed to authenticate the user NT Authority\Anonymous Logon in Active
Directory (Authentication=ActiveDirectoryIntegrated). Error code
0x4BC; state 10 The format of the specified domain name is invalid
According to your description, I found you used the Active Directory integrated authentication.
To use integrated Windows authentication, your domain’s Active Directory must be federated with Azure Active Directory. Your client application (or a service) connecting to the database must be running on a domain-joined machine under a user’s domain credentials
If you published the web app to Azure, Azure's web app server will not be in your domain’s Active Directory. So the SQL server will not pass the auth.
I suggest you could try to use Active Directory password authentication instead of the Active Directory integrated authentication.
Replace the connection string as below use azure AD user name and password. It will work well.
Server=tcp:brandotest.database.windows.net,1433;Initial Catalog=bradnotestsql;Persist Security Info=False;User ID={your_username};Password={your_password};MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Authentication="Active Directory Password";
Since the accepted answers are a bit dated, if you are out here in 2020 or later, the correct way for setting up integrated authentication is as follows:
(excerpted from here, the asp.net standard implementation)
https://learn.microsoft.com/en-us/azure/app-service/app-service-web-tutorial-connect-msi
add the Microsoft.Azure.Services.AppAuthentication nuget package.
modify your web.config by adding: (in configSections)
<section name="SqlAuthenticationProviders" type="System.Data.SqlClient.SqlAuthenticationProviderConfigurationSection, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
(and then)
<SqlAuthenticationProviders>
<providers>
<add name="Active Directory Interactive" type="Microsoft.Azure.Services.AppAuthentication.SqlAppAuthenticationProvider, Microsoft.Azure.Services.AppAuthentication" />
</providers>
</SqlAuthenticationProviders>
It's important to pay attention to the name you use there. Then... your connection string will look like:
<add name="MyEntities" connectionString="metadata=res://*/Data.MyDB.csdl|res://*/Data.MyDB.ssdl|res://*/Data.MyDB.msl;provider=System.Data.SqlClient;provider connection string="server=tcp:MyDB.database.windows.net;database=MyDB;UID=AnyString;Authentication=Active Directory Interactive;"" providerName="System.Data.EntityClient" />
The important notes are that the name you specify in the SqlAuthenticationProviders section must be the exact same name you use in the connection string for Authentication.
The other important note is that, coming from your old connection strings, you have to change Data Source to be Server, and Initial Catalog to be Database. UID=AnyString is necessary, or an exception is thrown.
Failure to follow these steps exactly will net you a lovely error:
System.Data.Entity.Core.EntityException: The underlying provider failed on Open. ---> System.AggregateException: One or more errors occurred. ---> System.AggregateException: One or more errors occurred. ---> AdalException: The format of the specified domain name is invalid.\r\n at ADALNativeWrapper.ADALGetAccessToken(String username, IntPtr password, String stsURL, String servicePrincipalName, ValueType correlationId, String clientId, Boolean* fWindowsIntegrated, Int64& fileTime)\r\n at System.Data.SqlClient.ActiveDirectoryNativeAuthenticationProvider.<>c__DisplayClass2_0.b__0()\r\n at System.Threading.Tasks.Task`1.InnerInvoke()\r\n at System.Threading.Tasks.Task.Execute()\r\n --- End of inner exception stack trace
At the first the error doesn't make sense, but once you see that the parameters were renamed from Data Source to Server, it does make sense.
Maybe all you need to use is token (certificate) authentication as explained on below resource:
https://github.com/Microsoft/sql-server-samples/tree/master/samples/features/security/azure-active-directory-auth/token
Try to register your application with Azure Active Directory as explained on that resource.
Hope this helps.

Sharepoint API Headless Obtaining Access Tokens

I am coding an integration that has to call Sharepoint-online API's. My integration is not a webapp and has to work without a user present.
As I understand it I need two setup steps:
1. User has to log in to Azure and set up an application and obtain a client ID.
2. I have to call a service with client ID and username and password I will then obtain an Access Token, Refresh Token and ID Token
Once the two setup steps are complete I then can call the service using the access token, but sometimes this will expire and I need to use the refresh token to get a new one.
Step 2 seems odd to me. Why isn't there a user interface where a user can log in and obtain the Access Refresh and ID tokens? Has someone built a utility website that just does this, or have I mis-understood something?
Thanks
Robert
The recommended OAuth flow for service and daemons apps is the Client Credential Flow (in that flow, there no refresh tokens involved; a client ID and a client secret is used to obtain an access token which eventually expires and then you need to get a new access token using the same client ID and secret). In the case of SharePoint Online, you have 2 options for this scenario:
SharePoint Online + Azure Access Control Service (ACS) integration. Details here. In short, you create a service principal (add in only policy) for instance at the site collection level - follow the "Creating the AppPrincipal" section in the blog I linked for this. Then you need to assign the specific permissions your app will need, in the application manifest. See a sample for that in the "Giving the App Principal Permissions" sections - again, you should first define what permissions your app needs. Then, you can use the service principal from a console application:
Program.cs
static void Main(string[] args)
{
Uri siteUri = new Uri("https://tenant.sharepoint.com/teams/test");
//Get the realm for the URL
string realm = TokenHelper.GetRealmFromTargetUrl(siteUri);
//Get the access token for the URL.
// Requires this app to be registered with the tenant
string accessToken = TokenHelper.GetAppOnlyAccessToken(
TokenHelper.SharePointPrincipal,
siteUri.Authority, realm).AccessToken;
HttpWebRequest endpointRequest =
(HttpWebRequest)HttpWebRequest.Create(
"https://tenant.sharepoint.com/teams/test/_api/web/lists/GetByTitle('Documents')/items");
endpointRequest.Method = "GET";
endpointRequest.Accept = "application/json;odata=verbose";
endpointRequest.Headers.Add("Authorization", "Bearer " + accessToken);
HttpWebResponse endpointResponse =
(HttpWebResponse)endpointRequest.GetResponse();
}
}
app.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<appSettings>
<add key="ClientId" value="65e674ca-3827-4134-852b-1196ff935e08"/>
<add key="ClientSecret" value="xxxxxxx"/>
</appSettings>
</configuration>
SharePoint Online + Azure Active Directory (AAD) integration. Details here. In that link you will find a sample code. The difference between the first approach is that in this one you are not using ACS but AAD. The permission that the app needs is defined in AAD - as of today, as far as I know, the application permissions that you can define in AAD are not as granular as the ones you can define via ACS - i.e. with ACS you can define an app at the site collection level, with AAD you can't the app will have tenant wide permissions (i.e. all site collections)

How to run a Service Fabric application with different security permissions?

Service Fabric RunAs feature
By default, a Service Fabric application will run with the Network Service account. Microsoft has (partial) documentation on how to run it with other permissions: RunAs: Run a Service Fabric application with different security permissions.
Based on this, here's what I'm trying to do:
My Service Fabric application calls a library that is being developed in an other repository.
When deployed in the cloud, the services will download the binaries for the library from a storage, unzip them in a working directory of the Service Fabric cluster and load it from there.
At development time, when I'm testing or debugging the application in a local cluster, I want the binaries for the library to be loaded from some folder on my local hard drive where I have just compiled them, that is right next to the source code.
The tricky part is that my company's security policies require the source code of said library to be accessible only to authorized users, which translates into the folder containing this code being read-protected. As a consequence my Service Fabric application, which runs as Network Service, can't access my binaries. Changing the security policies is not possible, nor giving Network Service access to the folder.
How can I configure my application so that it runs as a user that would have the correct access rights ?
Here's what I already tried:
Using a domain user
The easiest solution would be to be able to run the Service Fabric application with my own login. I tried this by adding the following to my ApplicationManifest.xml:
<Principals>
<Users>
<User Name="SfUser" AccountName="Domain\UserName" AccountType="DomainUser" Password="pass" />
</Users>
</Principals>
<Policies>
<DefaultRunAsPolicy UserRef="SfUser" />
</Policies>
This works: the application runs as Domain\UserName and can access all the folders I need. But this requires me to put my password in the configuration file, which is not satisfactory.
Using a local user
I then tried using a local user, thinking I would be able to configure access rights correctly using local user groups. The simplest version I could come up with is this:
<Principals>
<Users>
<User Name="SfUser" AccountName="LocalSfUser" AccountType="LocalUser">
<MemberOf>
<SystemGroup Name="MyLocalGroup"/>
</MemberOf>
</User>
</Users>
</Principals>
<Policies>
<DefaultRunAsPolicy UserRef="SfUser" />
</Policies>
I think this configuration is correct since when I deploy my application I can see in Windows user manager that several "technical" users where created by Service Fabric and that they belong to MyLocalGroup. However my application never starts.
I noticed several messages in Windows event viewer that seem related to the problem:
Logon Type: 8
Failure Information:
Failure Reason: The user has not been granted the requested logon type at this machine.
Process Information:
Caller Process Name: C:\Program Files\Microsoft Service Fabric\bin\FabricHost.exe
Apparently, "Logon Type 8" means "Network clear text logon". I suspect a local policy preventing this kind of logon in my company.
When you run as a localuser, this creates a random local user account on the machine. The reason this is most likely failing in the example above is the <SystemGroup Name="MyLocalGroup"/> needs to be a valid Windows system group such as "Administrators". You also do not really need the AccountName attribute above, but it does no harm.
To solve you issue of getting a file from a remote directory you need to use a domain user as you tried since a local user does not have a shared secret that can be verified with AD. The difference is that you can encrypt the password in the application manifest using a certificate that is deployed to the machine. I have put an example ApplicationManifest.xml snippet below, showing how the password for the domain user is encrypted with a certificate called "MyCert".
<Principals>
<Users>
<User Name="TestUser" AccountType="DomainUser" AccountName="Domain\User" Password="[Put Encrypted Password Here" PasswordEncrypted="true" />
</Users>
</Principals>
<Policies>
<DefaultRunAsPolicy UserRef="TestUser" />
<SecurityAccessPolicies>
<SecurityAccessPolicy ResourceRef="MyCert" PrincipalRef="TestUser" GrantRights="Full" ResourceType="Certificate" />
</SecurityAccessPolicies>
</Policies>
As a side note the article here https://azure.microsoft.com/en-us/documentation/articles/service-fabric-application-secret-management show how to create the encrypted password in settings.xml which is also often useful.

Jboss 5.1.0 EJB Security (unauthenticated principal via JNDI)

How do you secure remote EJBs from unauthenticated principal in JBoss-5.1.0.GA application server? After configuring my ejb security I can still access the remote EJBs with a JNDI lookup without principal and credentials passed in? This is a security risk. Essentially I want to disable all unauthenticated JNDI lookup on remote EJBs.
Here is my server/conf/login-config.xml configruation:
<application-policy name="<my security domain name>">
<authentication>
<login-module code="org.jboss.security.auth.spi.DatabaseServerLoginModule" flag="required">
<module-option name="dsJndiName">**java:jdbc/<my datasource name>**</module-option>
<module-option name="principalsQuery"><my users query></module-option>
<module-option name="rolesQuery"><my roles query></module-option>
<module-option name="debug">true</module-option>
</login-module>
</authentication>
</application-policy>
Here is my jboss.xml configruation in my ejb jar:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jboss PUBLIC
"-//JBoss//DTD JBOSS 5.0//EN"
"http://www.jboss.org/j2ee/dtd/jboss_5_0.dtd">
<jboss>
<security-domain><my security domain name from login-config></security-domain>
</jboss>
Here is how i do a a JNDI lookup to access my beans as a client
Note the principal and credentials are not being passed in to the context
Hashtable<String, String> props = new Hashtable<String, String>();
props.put(Context.INITIAL_CONTEXT_FACTORY,"org.jnp.interfaces.NamingContextFactory");
props.put(Context.URL_PKG_PREFIXES,"org.jboss.naming:org.jnp.interfaces");
props.put(Context.PROVIDER_URL,"jnp://localhost:1099");
//props.put(Context.SECURITY_PRINCIPAL,"");
//props.put(Context.SECURITY_CREDENTIALS,"");
ctx = new InitialContext(props);
ctx.lookup("<earname>/<ejb interface definition>/remote">
What is the issue?
When no/wrong principal/credentials are passed the user is authenticated as an anonymous principal and has full access to the remote EJBs via JNDI
What I tried already to fix the issue:
i deleted the following line from all login modules in my server/conf/login-config.xml but it had no effect
<module-option name="unauthenticatedIdentity">anonymous</module-option>
i deleted following line from server/conf/jboss-service.xml thinking it will resolve the issue, but it had no effect
<attribute name="DefaultUnauthenticatedPrincipal">anonymous</attribute>
i deleted application policy "client-login" from login-config.xml that is in there by default since i am using a DatabaseLoginModule
My jboss-ejb-policy and jboss-web-policy in server/depoly/security/security-policies-jboss-beans.xml are extending my DatabaseLoginModule policy in login-config.xml
I have no security related annotations in my ejb classes/interfaces
Other things to note
I tested this scenario in Jboss-as-7.1.1.final and i get EjbAccessException: invalid User which is correct (you add this to the jboss-ejb3.xml it will secure all EJBs via the security domain)
<assembly-descriptor>
<s:security>
<ejb-name>*</ejb-name>
<s:security-domain><security domain name here></s:security-domain>
</s:security>
</assembly-descriptor>
the issue here is NOT authorization but authentications all ejb security annotations do not help
what i want to do is prevent the anonymous principal completely from making JNDI call
I have enabled TRACE logging on org.jboss.security and i can see that when ever i call the JNDI i get the following hit in the logs
Principal: anonymous:callerRunAs=null:callerRunAs=null:ejbRestrictionEnforcement=false:ejbVersion=null]; policyRegistration=org.jboss.security.plugins.JBossPolicyRegistration#1f51a2f;
I have verified all my configurations work and the DatabaseLoginModule works when i use the programmatic login through WebAuthetication
Even when passing the initial context a valid principal/credential from database the anonymous principal is used indicating that the principal/credential is not even processed by the context
I can probably secure my EJBs through #RolesAllowed #DeclareRoles ... but like i mentioned this would be an authorization concern not authentication and also if I have many roles and EJBs this would not be good as far as maintainability
How can I disable/prevent unauthenticated anonymous JNDI lookup for the entire application like it automatically does in JBoss 7.1.1? I know I can upgrade my application server as one solution but I don't have the option to do so. This should be possible and easy to do in Jboss 5.1.0. but i have looked for the answer everywhere and I can't find it? Thanks for your help.

Automatic login with HttpServletRequest and LDAP

I have a JSF web application that uses cookies for automatic authentication without prompting for username & password. It uses a cookie with username and a random UUID, and uses a WebFilter for redirection.
When there are no cookies on the client side, the authentication is done through HttpServletRequest #login(String username, String password). Behind the scenes, this approach uses JAAS authentication, and uses a LDAP server behind.
My problem comes when my application recognizes the user through the cookies holding the userid and the UUID. In this situation,
the application doesn't know the password, so the method HttpServletRequest #login(String username, String password) cannot be used.
Should I ask the password to the LDAP server through JNDI? This doesn't seem to be possible at a first glance
Alternatively, I could store the password in my db. But this would mean duplication of information, and I don't like it.
I have seen around people simply setting the attribute "role" to the session, but this doesn't seem to be equivalent to a JAAS login. With "equivalent" I mean being able to use isUserInRole() and getUserPrincipal() methods.
So, the question is: how am I supposed to log in the user in this case? I hope that the question is clearer now.
EDIT
In order to let the code speak, I add a simplified version of the Managed Bean:
#ManagedBean
#SessionScoped
public class loginBean() {
private String username = null;
private String password = null;
private UUID uuid = null;
private boolean rememberMe = false;
public void doLogin() {
checkCookies(); // this method sets the property values after checking if
// username & uuid match the ones saved previously
if (username != null && uuid != null && rememberMe) {
// authenticate automatically. Here I don't know how to proceed, because
// I don't have the password, unless I have saved it in the application's db,
// duplicating it because it's already in LDAP server.
} else {
httpServletRequest.login(username, password); // this uses LDAP behind JAAS
createCookies(); // this method also saves username & uuid in the app's db
}
}
To do an actual container login in a custom way (in your case via an cookie and UUID instead of the password), you need to create your own login module.
The dedicated API in Java EE for this is JASPI/JASPIC (people can never quite agree on the name, complicating eg google queries).
A login module is in full control and does not have to authenticate with the ldap server (if your app can locally verify with 100% certainty that the cookie is valid). You probably do have to authorize the user (ask the ldap server for the roles/groups the user has).
As an alternative to JASPI/JASPIC you can also look at the proprietary login module mechanism that your server is using.
Using an LDAP entry for this case is equivalent to requesting that the directory server authenticate a connection using information provided by the application. In terms of LDAP, authenticate means that an existing LDAP session, that is, a connection to a directory server, has had its authentication state changed by a successful BIND request.
The web application should request appropriate information from the user to be authenticated and present this information to the directory server as a BIND request. The information required varies according to the authentication method used by the web application (LDAP client):
A simple BIND request requires a distinguished name and a password. This distinguished name and password should be transmitted to the directory server as a simple BIND request over a secure connection.
A SASL BIND request using a predefined SASL mechanism. The mechanisms vary per server and range from GSSAPI to PLAIN.
Upon receipt of the BIND request, the directory server will immediately change the authentication state of the connection to anonymous and process the BIND request. If the request can be successfully processed, the directory server responds to the LDAP with a BIND response including an integer result code of zero (0). This indicates that the distinguished name or username was able to successfully authenticate.
The web application should use some mechanism to maintain an authentication state and issue a BIND request to the directory server when the authentication state changes. This could be a session timeout, or some other mechanism. The method that is chosen should not be changeable by the user.
In summary, use the directory server to check authentication credentials and use the session framework to manage authentication state.
Edit:
Seems this was a controversial answer.
Using cookies does not handle the case of the browser having cookies disabled, and cookies are not necessary to maintain an authentication state when using sessions.
The session does not need the password, nor should it store any sensitive information like passwords in memory or sessions. The application should request the password when the authentication state expires (if ever) or the session expires (if ever).

Resources