JNDI: ApacheDS: INVALID_CREDENTIALS: DIGEST-MD5: digest response format violation. Mismatched URI: ldap/localhost; expecting: ldap/ldap.example.com - jndi

I am trying to authenticate user using JNDI, security level as SASL. Following is my sample code.
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
public class Test {
private static final String CONTEXT_FACTORY = "com.sun.jndi.ldap.LdapCtxFactory";
private static final String PROVIDER_URL = "ldap://localhost:10389";
private static final String SECURITY_AUTHENTICATION = "DIGEST-MD5";
public static void main(String[] args) throws NamingException {
Hashtable<String, String> env = new Hashtable<String, String>(11);
env.put(Context.INITIAL_CONTEXT_FACTORY, CONTEXT_FACTORY);
env.put(Context.PROVIDER_URL, PROVIDER_URL);
env.put(Context.SECURITY_AUTHENTICATION, SECURITY_AUTHENTICATION);
env.put(Context.SECURITY_PRINCIPAL,
"cn=Krishna,ou=people,dc=example,dc=com");
env.put(Context.SECURITY_CREDENTIALS, "password123");
try {
DirContext ctx = new InitialDirContext(env);
System.out.println("Authentication Successful");
ctx.close();
} catch (NamingException e) {
System.out.println("Authentication Failed");
e.printStackTrace();
}
}
}
I encrypted the password using MD5 algorithm in directory. When I tried to run above program, I am getting following error.
Authentication Failed
javax.naming.AuthenticationException: [LDAP: error code 49 - INVALID_CREDENTIALS: DIGEST-MD5: digest response format violation. Mismatched URI: ldap/localhost; expecting: ldap/ldap.example.com]
at com.sun.jndi.ldap.LdapCtx.mapErrorCode(LdapCtx.java:3135)
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:3081)
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2883)
at com.sun.jndi.ldap.LdapCtx.connect(LdapCtx.java:2797)
at com.sun.jndi.ldap.LdapCtx.<init>(LdapCtx.java:319)
at com.sun.jndi.ldap.LdapCtxFactory.getUsingURL(LdapCtxFactory.java:192)
at com.sun.jndi.ldap.LdapCtxFactory.getUsingURLs(LdapCtxFactory.java:210)
at com.sun.jndi.ldap.LdapCtxFactory.getLdapCtxInstance(LdapCtxFactory.java:153)
at com.sun.jndi.ldap.LdapCtxFactory.getInitialContext(LdapCtxFactory.java:83)
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:684)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:313)
at javax.naming.InitialContext.init(InitialContext.java:244)
at javax.naming.InitialContext.<init>(InitialContext.java:216)
at javax.naming.directory.InitialDirContext.<init>(InitialDirContext.java:101)
at jndi_tutorial.Test.main(Test.java:26)
But when i tried to authenticate using simple mechanism (SECURITY_AUTHENTICATION = "simple"), My authentication is success. Is there any configurations I am missing?

Check if your LDAP server supports DIGEST-MD5 SASL mechanism.
DirContext ctx = new InitialDirContext();
Attributes attrs = ctx.getAttributes("ldap://<HSOT>:<PORT>", new String[]{"supportedSASLMechanisms"});
Check if the passwords are in fact stored as MD5 digest/hash in the LDAP server.
Connect to the LDAP sever with an LDPAP browser like Apache Dir Studio and check the password attribute. It will be prefixed with hash mechanism used.

Related

Can someone help how to create graph client using token of IAuthenticationResult (msal4j)

Using ADAL library in Java , I created token (using client credential provider) ,the resulted token is TokenCredentialAuthProvider which is of IAuthenticationProvider type. this token i was able to use to create a graph client.
But as i want to migrate from ADAL to MSAL ,I tried creating a token using MSAL4j (java) (using client credential provider) and the resulted token was of the form IAuthenticationResult , which i cant use to create Graph client as it requires an instance of IAuthenticationProvider.
how to create graph client using token of the form IAuthenticationResult (msal4j)
MS Graph clients creation require an instance of IAuthenticationProvider. Several built-in providers and samples are available in Choose a Microsoft Graph authentication provider based on scenario. If you already posses an token you can create your own class/implementation and return the token returned by IAuthenticationResult.getAccessToken() from within the getAuthorizationTokenAsync method.
E.g.
// MyAuthenticationProvider.java
package com.example;
import java.net.URL;
import java.util.concurrent.CompletableFuture;
import com.microsoft.graph.authentication.IAuthenticationProvider;
public class MyAuthenticationProvider implements IAuthenticationProvider {
private CompletableFuture<String> accessTokenFuture;
public MyAuthenticationProvider(String accessToken) {
this.accessTokenFuture = new CompletableFuture<>();
this.accessTokenFuture.complete(accessToken);
}
#Override
public CompletableFuture<String> getAuthorizationTokenAsync(URL requestUrl) {
return this.accessTokenFuture;
}
}
// App.java
package com.example;
import com.google.gson.Gson;
import com.microsoft.graph.authentication.IAuthenticationProvider;
import com.microsoft.graph.models.User;
import com.microsoft.graph.requests.GraphServiceClient;
public class App {
public static void main(String[] args) {
String msalAccessToken = args[0];
final IAuthenticationProvider auth = new MyAuthenticationProvider(msalAccessToken);
final GraphServiceClient graphClient = GraphServiceClient
.builder()
.authenticationProvider(auth)
.buildClient();
final User me = graphClient.me().buildRequest().get();
System.out.println(new Gson().toJson(me));
}
}

Azure AD SAML Authentication with Spring Security 5.3.2 (not SAML Extension)

I am attempting to replace CAS with Azure Active Directory SAML authentication (SSO) in a Spring Boot API. My version of Spring Security is 5.3.2. Spring boot is 2.3.0.
Documentation has been hard to find. I think this is explained by 8685. I found 8010 and attempted the workaround mentioned there, but my breakpoints there are not getting hit.
Given the current state of the transition from SAML Extension to Spring Security, should I be using the old SAML Extension? I can reach my "success" endpoint with a JSESSIONID and SAMLReponse, but it's encrypted. Is this something I need to do myself? (If so, how?) The SecurityContext / user details are not getting set. I see AccessDenied stack traces in my logs, but I think that's a symptom of the Anonymous user context.
Relevant code is below. I have application.yml and application.properties files, but all config is annotations-based. If you see anything way off base, please let me know! Any guidance would be appreciated.
Here is my SecurityConfig:
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
RelyingPartyRegistration getSaml2AuthenticationConfiguration() throws Exception {
// remote IDP entity ID
String idpEntityId = "https://sts.windows.net/xxxxxxxxxxxx/";
// remote WebSSO Endpoint - Where to Send AuthNRequests to
String webSsoEndpoint = "https://login.microsoftonline.com/xxxxxxxxxxxx/saml2";
// local registration ID
String registrationId = "xxxxxxxxxxxx";
// local entity ID - autogenerated based on URL
String localEntityIdTemplate = "xxxxxxxxxxxx.local";
// local signing (and decryption key)
Saml2X509Credential signingCredential = getSigningCredential(); //private method not included
// IDP certificate for verification of incoming messages
Saml2X509Credential idpVerificationCertificate = getVerificationCertificate(); //private method not included
String acsUrlTemplate = "https://xxxxxxxxxxxx.local/success"; //REST endpoint, see below
return RelyingPartyRegistration.withRegistrationId(registrationId)
.providerDetails(config -> config.entityId(idpEntityId))
.providerDetails(config -> config.webSsoUrl(webSsoEndpoint)).credentials(c -> c.add(signingCredential))
.credentials(c -> c.add(idpVerificationCertificate)).localEntityIdTemplate(localEntityIdTemplate)
.assertionConsumerServiceUrlTemplate(acsUrlTemplate).build();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// Just a test
OpenSamlAuthenticationProvider provider = new OpenSamlAuthenticationProvider();
http
.headers()
.frameOptions()
.sameOrigin()
.httpStrictTransportSecurity()
.disable()
.and()
.authorizeRequests()
//... more antMatchers and permitAlls
.antMatchers("/success").permitAll()
.antMatchers("/login").permitAll()
.antMatchers("/logout").permitAll()
.antMatchers("/error").permitAll().anyRequest().authenticated().and()
.csrf().disable()
.saml2Login(
saml2 -> {
try {
saml2
.authenticationManager(a -> {
// This code is never reached
Authentication result = provider.authenticate(a);
Saml2Authentication saml2Authentication = (Saml2Authentication) result;
return result;
}).relyingPartyRegistrationRepository(
new InMemoryRelyingPartyRegistrationRepository(getSaml2AuthenticationConfiguration())
)
.loginProcessingUrl("/login/{registrationId}");
} catch (Exception e) {
// It made me put this try/catch here... this isn't getting reached either
e.printStackTrace();
}
});
}
}
And my REST endpoint:
#RestController
public class HelloController {
#RequestMapping(value = "/success", method=RequestMethod.POST)
public String saml2Post(HttpServletRequest request) throws IOException {
String jSessionId = request.getHeader("cookie");
System.out.println(jSessionId);
String samlResponse = request.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
System.out.println(samlResponse);
return "login success";
}
}
And my gradle dependencies (Gradle 6.5):
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-security'
compile 'org.springframework.security:spring-security-config'
compile 'org.springframework.security:spring-security-saml2-service-provider'
compile 'org.springframework.boot:spring-boot-starter-thymeleaf'
compile 'org.springframework.boot:spring-boot-starter-web'
compile 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5'
implementation 'org.springframework.boot:spring-boot-starter-freemarker'
implementation 'org.springframework.boot:spring-boot-starter-integration'
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
implementation 'org.springframework.boot:spring-boot-starter-mail'
compile 'org.springframework.security:spring-security-oauth2-client'
compile 'org.springframework.security:spring-security-oauth2-jose'
implementation 'joda-time:joda-time:2.10.6'
implementation 'com.google.guava:guava:29.0-jre'
implementation 'com.opencsv:opencsv:5.2'
implementation 'org.apache.commons:commons-lang3:3.10'
implementation 'net.minidev:json-smart:2.3'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'com.microsoft.sqlserver:mssql-jdbc'
runtimeOnly 'org.hsqldb:hsqldb'
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
testImplementation 'org.springframework.integration:spring-integration-test'
testImplementation 'org.springframework.security:spring-security-test'
}

How to check oauth credentials are valid or not in Netsuite?

I could get access token and secret, but they are not working some times . I am getting error like invalid login attempt. I don't know how to solve this issue.
I have all the credentials for oauth , these are
Consumer key
Consumer secret
Account id
Token id
Token Secret
Script id
Deployment id
I want to know my oauth credentials by group or individual are valid or not .
I think the only way is to hit SuiteTalk or RESTlet.
If you are using RESTlet, you must ensure that the user has access to RESTlet in the deployment options.
I have a working code using Java (using Scribe Java Library) which can be found here
MAIN Method:
OAuthConfig authConfig = new OAuthConfig("CONSUMER_KEY", "CONSUMER_SECRET", null, SignatureType.Header, null, null);
Token token = new Token("TOKEN_ID", "TOKEN_SECRET");
OAuth10aServiceImpl auth10aServiceImpl = new OAuth10aServiceImpl(new NetSuiteApi(), authConfig);
OAuthRequest request = new OAuthRequest(Verb.GET, "RESTLET_URL");
request.setRealm("NS_ACCOUNT_ID");
auth10aServiceImpl.signRequest(token, request);
Response response = request.send();
Also you will need to write NetSuiteApi Class extending DefaultApi10a
import org.scribe.builder.api.DefaultApi10a;
import org.scribe.model.Token;
public class NetSuiteApi extends DefaultApi10a {
#Override
public String getAccessTokenEndpoint() {
// TODO Auto-generated method stub
return null;
}
#Override
public String getAuthorizationUrl(Token arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public String getRequestTokenEndpoint() {
// TODO Auto-generated method stub
return null;
}
}

how to get the user's timeline of one's own twitter account through twitter api in java

I had been trying to get my timeline messages through some Java code explained in the http://www.dreamincode.net/forums/blog/114/entry-4459-demo-of-twitter-application-only-oauth-authentication-using-java blog and wrote some code in Java.
I am using application-only authentication and using consumer key and consumer secret. Here is a portion of my code where I am requesting the bearer token:
bearerToken=requestBearerToken("https://api.twitter.com/1.1/statuses/besra_u_timeline.json");
Is this the right way? I ask because in the requestBearerToken method
private static String requestBearerToken(String endPointUrl) throws IOException {
HttpsURLConnection connection = null;
URL url = new URL(endPointUrl);
connection = (HttpsURLConnection) url.openConnection();
try {
connection.getInputStream();
} catch(IOException e){
System.out.println("IOException");
}
I am constantly getting an IOException which means that I am not getting the input stream from the connection object. Please help me to get the tweets.
Ya i have got a way to do it using the twitter4j api.Consumer key , consumer secret, access token and access secret u can get once u register ur app in dev.twitter.com/apps
import twitter4j.ResponseList;
import twitter4j.Status;
import twitter4j.Twitter;
import twitter4j.Status;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.conf.ConfigurationBuilder;
public class SimpleCrawler {
static ResponseList<Status> statuses;
public static void main(String[] args) throws TwitterException {
ConfigurationBuilder cb=new ConfigurationBuilder();
cb.setDebugEnabled(true)
.setOAuthConsumerKey("your consumer key")
.setOAuthConsumerSecret("your con secret")
.setOAuthAccessToken("your access token")
.setOAuthAccessTokenSecret("access token secret");
TwitterFactory tf=new TwitterFactory(cb.build());
Twitter tw = tf.getInstance();
try {
statuses=tw.getHomeTimeline();
System.out.println("Connected to twitter");
} catch (TwitterException e) {
System.out.println("Cannot connect to Twitter");
System.exit(0);
}
System.out.println("Reading TimeLine...");
for(Status st1:statuses){
String data[]={st1.getUser().getName(),String.valueOf(st1.getCreatedAt()),twtmsg};
System.out.println(data);
}
}
}
Through twitter api also its possible but don't know . One problem with this method is that it fetches 20 tweets only at a time ,any help would be appreciated.suggestions are most welcome plz comment.
You need to use Paging:
Paging paging = new Paging();
paging.setPage(1);
ResponseList<Status> statuses = twitter.getHomeTimeline(paging);
System.out.println(statuses.size());
paging.setPage(2);
statuses.addAll(twitter.getHomeTimeline(paging));
System.out.println(statuses.size());
The above simplified code will give you two pages worth of statuses

How to propagate spring security context to JMS?

I have a web application which sets a spring security context through a spring filter. Services are protected with spring annotations based on users roles. This works.
Asynchronous tasks are executed in JMS listeners (extend javax.jms.MessageListener). The setup of this listeners is done with Spring.
Messages are sent from the web application, at this time a user is authenticated. I need the same authentication in the JMS thread (user and roles) during message processing.
Today this is done by putting the spring authentication in the JMS ObjectMessage:
SecurityContext context = SecurityContextHolder.getContext();
Authentication auth = context.getAuthentication();
... put the auth object in jms message object
Then inside the JMS listener the authentication object is extracted and set in the context:
SecurityContext context = new SecurityContextImpl();
context.setAuthentication(auth);
SecurityContextHolder.setContext(context);
This works most of the time. But when there is a delay before the processing of a message, message will never be processed. I couldn't determine yet the cause of these messages loss, but I'm not sure the way we propagate authentication is good, even if it works in custer when the message is processed in another server.
Is this the right way to propagate a spring authentication ?
Regards,
Mickaƫl
I did not find better solution, but this one works for me just fine.
By sending of JMS Message I'am storing Authentication as Header and respectively by receiving recreating Security Context. In order to store Authentication as Header you have to serialise it as Base64:
class AuthenticationSerializer {
static String serialize(Authentication authentication) {
byte[] bytes = SerializationUtils.serialize(authentication);
return DatatypeConverter.printBase64Binary(bytes);
}
static Authentication deserialize(String authentication) {
byte[] decoded = DatatypeConverter.parseBase64Binary(authentication);
Authentication auth = (Authentication) SerializationUtils.deserialize(decoded);
return auth;
}
}
By sending just set Message header - you can create Decorator for Message Template, so that it will happen automatically. In you decorator just call such method:
private void attachAuthenticationContext(Message message){
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String serialized = AuthenticationSerializer.serialize(auth);
message.setStringProperty("authcontext", serialized);
}
Receiving gets more complicated, but it can be also done automatically. Instead of applying #EnableJMS use following Configuration:
#Configuration
class JmsBootstrapConfiguration {
#Bean(name = JmsListenerConfigUtils.JMS_LISTENER_ANNOTATION_PROCESSOR_BEAN_NAME)
#Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public JmsListenerAnnotationBeanPostProcessor jmsListenerAnnotationProcessor() {
return new JmsListenerPostProcessor();
}
#Bean(name = JmsListenerConfigUtils.JMS_LISTENER_ENDPOINT_REGISTRY_BEAN_NAME)
public JmsListenerEndpointRegistry defaultJmsListenerEndpointRegistry() {
return new JmsListenerEndpointRegistry();
}
}
class JmsListenerPostProcessor extends JmsListenerAnnotationBeanPostProcessor {
#Override
protected MethodJmsListenerEndpoint createMethodJmsListenerEndpoint() {
return new ListenerEndpoint();
}
}
class ListenerEndpoint extends MethodJmsListenerEndpoint {
#Override
protected MessagingMessageListenerAdapter createMessageListenerInstance() {
return new ListenerAdapter();
}
}
class ListenerAdapter extends MessagingMessageListenerAdapter {
#Override
public void onMessage(Message jmsMessage, Session session) throws JMSException {
propagateSecurityContext(jmsMessage);
super.onMessage(jmsMessage, session);
}
private void propagateSecurityContext(Message jmsMessage) throws JMSException {
String authStr = jmsMessage.getStringProperty("authcontext");
Authentication auth = AuthenticationSerializer.deserialize(authStr);
SecurityContextHolder.getContext().setAuthentication(auth);
}
}
I have implemented for myself a different solution, which seems easier for me.
Already I have a message converter, the standard JSON Jackson message converter, which I need to configure on the JMSTemplate and the listeners.
So I created a MessageConverter implementation which wraps around another message converter, and propagates the security context via the JMS message properties.
(In my case, the propagated context is a JWT token which I can extract from the current context and apply to the security context of the listening thread).
This way the entire responsibility for propagation of security context is elegantly implemented in a single class, and requires only a little bit of configuration.
Thanks great but I am handling this in easy way . put one util file and solved .
public class AuthenticationSerializerUtil {
public static final String AUTH_CONTEXT = "authContext";
public static String serialize(Authentication authentication) {
byte[] bytes = SerializationUtils.serialize(authentication);
return DatatypeConverter.printBase64Binary(bytes);
}
public static Authentication deserialize(String authentication) {
byte[] decoded = DatatypeConverter.parseBase64Binary(authentication);
Authentication auth = (Authentication) SerializationUtils.deserialize(decoded);
return auth;
}
/**
* taking message and return string json from message & set current context
* #param message
* #return
*/
public static String jsonAndSetContext(Message message){
LongString authContext = (LongString)message.getMessageProperties().getHeaders().get(AUTH_CONTEXT);
Authentication auth = deserialize(authContext.toString());
SecurityContextHolder.getContext().setAuthentication(auth);
byte json[] = message.getBody();
return new String(json);
}
}

Resources