IDP Initiated SSO not working in spring security SAML sample app - spring-security

I have a fork of spring security saml project. You can see the changes I've applied here: https://github.com/troyhart/spring-security-saml/commits/nwri-sample_simple.
The SP urn:troyhart:nwri is registered at SSO Circle. If you have an SSO Circle login you can fire up the application and test that SP Initiated SSO works. However, I can not get IDP Initiated SSO to work. I get the following exception:
org.springframework.security.authentication.AuthenticationServiceException: Error determining metadata contracts
at org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:91)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:195)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:166)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.saml.metadata.MetadataGeneratorFilter.doFilter(MetadataGeneratorFilter.java:87)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.opensaml.saml2.metadata.provider.MetadataProviderException: Metadata for issuer http://idp.ssocircle.com wasn't found
at org.springframework.security.saml.processor.SAMLProcessorImpl.retrieveMessage(SAMLProcessorImpl.java:108)
at org.springframework.security.saml.processor.SAMLProcessorImpl.retrieveMessage(SAMLProcessorImpl.java:172)
at org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:77)
... 29 more
What's strange is that the exception indicates that the sample application thinks the IDP EntityID is http://idp.ssocircle.com, but the real EntityID for SSO Circle is https://idp.ssocircle.com.
Does anyone know what's going on here? The thing that is strange is that I have tested that IDP initiated does work, but at some point it stopped working and now it fails every time with the given exception. Please help! I'm at a total loss.

The issue is that the quick-start quide references a deprecated metaAlias in the documented IDP-initiated SSO URL for SSO Circle. The new value is /publicidp.
The URL should therefore be:
https://idp.ssocircle.com:443/sso/saml2/jsp/idpSSOInit.jsp?metaAlias=/publicidp&spEntityID=replaceWithUniqueIdentifier
I've submitted a pull request for the fix.

Related

Why is my web app trying to connect to SQL Server Express when it's not supposed to?

I developed an ASP.NET MVC application that uses Microsoft's ASP.NET Identity with Oracle (not SQL Server). The application runs fine on my localhost, but when I publish it to the server (Windows 2008 R2), it throws this error shown below. It used to work before on the server; this error just started happening all of a sudden. The datastore for the Identity stuff is Oracle, not SQL Server Express. I don't have any connection string in my web.config that uses SQL Server Express.
A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 26 - Error Locating Server/Instance Specified)
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
SQL Server Express database file auto-creation error:
The connection string specifies a local Sql Server Express instance using a database location within the application's App_Data directory. The provider attempted to automatically create the application services database because the provider determined that the database does not exist. The following configuration requirements are necessary to successfully check for existence of the application services database and automatically create the application services database:
If the application is running on either Windows 7 or Windows Server 2008R2, special configuration steps are necessary to enable automatic creation of the provider database. Additional information is available at: http://go.microsoft.com/fwlink/?LinkId=160102. If the application's App_Data directory does not already exist, the web server account must have read and write access to the application's directory. This is necessary because the web server account will automatically create the App_Data directory if it does not already exist.
If the application's App_Data directory already exists, the web server account only requires read and write access to the application's App_Data directory. This is necessary because the web server account will attempt to verify that the Sql Server Express database already exists within the application's App_Data directory. Revoking read access on the App_Data directory from the web server account will prevent the provider from correctly determining if the SQL Server Express database already exists. This will cause an error when the provider attempts to create a duplicate of an already existing database. Write access is required because the web server account's credentials are used when creating the new database.
SQL Server Express must be installed on the machine.
The process identity for the web server account must have a local user profile. See the readme document for details on how to create a local user profile for both machine and domain accounts.
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.
Stack Trace:
System.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, SqlCredential credential, Object providerInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString userConnectionOptions, SessionData reconnectSessionData, DbConnectionPool pool, String accessToken, Boolean applyTransientFaultHandling, SqlAuthenticationProviderManager sqlAuthProviderManager) +1524
System.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions) +706
System.Data.ProviderBase.DbConnectionFactory.CreateNonPooledConnection(DbConnection owningConnection, DbConnectionPoolGroup poolGroup, DbConnectionOptions userOptions) +57
System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection) +1186
System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions) +315
System.Data.SqlClient.SqlConnection.TryOpenInner(TaskCompletionSource`1 retry) +128
System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry) +265
System.Data.SqlClient.SqlConnection.Open() +133
System.Web.Management.SqlServices.GetSqlConnection(String server, String user, String password, Boolean trusted, String connectionString) +82
[HttpException (0x80004005): Unable to connect to SQL Server database.]
System.Web.Management.SqlServices.GetSqlConnection(String server, String user, String password, Boolean trusted, String connectionString) +175
System.Web.Management.SqlServices.SetupApplicationServices(String server, String user, String password, Boolean trusted, String connectionString, String database, String dbFileName, SqlFeatures features, Boolean install) +121
System.Web.Management.SqlServices.Install(String database, String dbFileName, String connectionString) +57
Found the problem - I had put this setting in my Web.config:
<roleManager enabled="true"
Since roleManager is a provider set in Machine.config to use SQL Express, my app in turn tried o use SQL Express. As soon as I removed that roleManager setting from my web.config, my app worked. I guess you could also try to set it to enabled="false", but I just took it all out since I have no use for it.

Listing several authentication providers within the same authentication manager

I came across this code snippet while debugging an authentication problem :
<security:authentication-manager>
<security:authentication-provider user-service-ref="userDetailsService">
<security:password-encoder hash="sha-256">
<security:salt-source user-property="dateCreated" />
</security:password-encoder>
</security:authentication-provider>
<security:authentication-provider ref="ldapAuthProvider" />
</security:authentication-manager>
What I have noticed while debugging and playing around with the user credentials is that if the first authentication-provider (i.e. userDetailsService) fails to authenticate my user, a remote call is then made to my LDAP server to try to authenticate my user. However if the first authentication-provider manages to authenticate my user successfully, the second authentication-provider is never called.
My question is does the listing of these authentication providers work in a way that if one fails we should jump to the next? I also wonder if the order of them authentication providers listed within the authentication manager plays a role (from a priority standpoint)? An extra reference from Spring Security's official documentation will be more than appreciated.
From the Spring Security reference documentation:
Each AuthenticationProvider has an opportunity to indicate that authentication should be successful, fail, or indicate it cannot make a decision and allow a downstream AuthenticationProvider to decide. If none of the configured AuthenticationProviders can authenticate, then authentication will fail (...)
In practice each AuthenticationProvider knows how to perform a specific type of authentication. For example, one AuthenticationProvider might be able to validate a username/password, while another might be able to authenticate a SAML assertion.
When multiple AuthenticationProviders are defined, they will be queried in the order they are declared.
If the first AuthenticationProvider cannot come to a conclusion it will allow the next AuthenticationProvider to try.

How to pass token while calling EWS endpoint using proxy generated classes (ExchangeServicePortTypeClient) not through EWSManagedAPI

I am having a console application which uses Exchange Web Services OnPrem using proxy generated classes like below
var client = new ExchangeServicePortTypeClient("EndPointConfigName", ".XXXXX.asmx");
It works fine. Now I want to do the same for Exchange Online but with that it's OAuth authentication and requires token to pass.
I am generating token using registered application id, tenant id and certificate however, not sure how exactly I can add it with "ExchangeServicePortTypeClient" object.
I see ExchangeServicePortTypeClient has some token specific properties but not getting how exactly I can do.
Due to that I am getting exception "The HTTP request is unauthorized with client authentication scheme 'Negotiate'. The authentication header received from the server was 'Basic Realm=""'".
I believe i would need some changes in my binding(tried both basichhttpbinding and wshttpbinding) as well but not getting what would work for OAuth authentication.
Just sample. I tried with all the possible options like Windows, Basic, None, Certificate...
<security mode="Transport">
<transport clientCredentialType="Windows" proxyCredentialType="Basic" realm="*" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
Can you please suggest how I can achieve this ?
Please note I am able to do this using EWSManagedAPI as well as Service call using "HttpWebRequest" [passing token like getFolderRequest.Headers.Add("Authorization", "Bearer " + accessToken);]
However, my requirement is to do using proxy generated classes.

Securing REST endpoint using spring security

I am trying to provide security to the REST endpoints. I am following instructions from this page. In my case I don't have view hence I haven't created controller to specify the views and haven't added viewResolver in my AppConfig.java
After implementation it correctly shows the access denied error upon calling a secured REST endpoint. But even though I specify username/password in the request header I get the access denied error. I am testing in postman setting username/password in Basic Auth. What am I missing any idea?
The example you have followed is implementing a form-based authentication. In order to change it to http auth (which is more suitable for REST services) you need to look for the following form-login tag in your security.xml:
<form-login
login-page="/login"
default-target-url="/welcome"
authentication-failure-url="/login?error"
username-parameter="username"
password-parameter="password" />
And just change it to an empty http-basic tag:
<http-basic />
If you did not change anything else, then it supposed to work perfectly. You can also test your setup from your browser, by trying to access your page. If you configured everything properly you will get a popup this time, not a form. That will be HTTP-basic authentication welcoming you.
Since likely you are using the Java-based configuration, the equivalent of this change would be to replace:
http.authorizeRequests()
.antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")
.antMatchers("/dba/**").access("hasRole('ROLE_ADMIN') or hasRole('ROLE_DBA')")
.and().formLogin();
with:
http.authorizeRequests()
.antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")
.antMatchers("/dba/**").access("hasRole('ROLE_ADMIN') or hasRole('ROLE_DBA')")
.and().httpBasic();

Stack trace when using Spring Security

I'm using Spring Security for user authentication in my web app and I noticed this in my stack trace:
[DEBUG] [http-bio-8080-exec-3 10:48:02] (ExceptionTranslationFilter.java:handleSpringSecurityException:165) Access is denied (user is anonymous); redirecting to authentication entry point
org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:83)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:206)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)
etc...
Is this normal behavior? I now it's not an error, but it looks similar :)
It is a debug message that tell you spring is redirecting to login page because of an anonymous access to a restricted area.
You can change the log level for org.springframework.security packege if you want, but this is a normal behaviour
Yes, this is normal; note that this is not an error, only a debug.
This is how Spring's filter-chain works - when one filter fails, it returns to the next chain. In this case it is the ExceptionTranslationFilter that fails, and now the authentication filter (UsernamePasswordFilter?) attempts to authenticate the user.

Resources