I am trying to implement SAML SLO with OKTA , i am able to integrate SSO Login using OpenSAML4 but to implement SLO with Okta ,i am not getting proper resource.
My project is servlet based only and for logout Rest endpoint is already created which is called from react UI and invalidates session .
https://blog.samlsecurity.com/2012/11/verifying-signatures-with-opensaml.html
i am following the above blog , but it seems i am missing something , is there any resource or working example which i can refer or any improvement in the mentioned blog which can help me to implement SLO
private void redirectUserWithRequest(HttpServletResponse httpServletResponse, AuthnRequest authnRequest) {
MessageContext context = new MessageContext();
context.setMessage(authnRequest);
SAMLBindingContext bindingContext = context.getSubcontext(SAMLBindingContext.class, true);
bindingContext.setRelayState("teststate");
SAMLPeerEntityContext peerEntityContext = context.getSubcontext(SAMLPeerEntityContext.class, true);
SAMLEndpointContext endpointContext = peerEntityContext.getSubcontext(SAMLEndpointContext.class, true);
endpointContext.setEndpoint(URLToEndpoint(MESSAGE_RECEIVER_ENDPOINT));
HTTPRedirectDeflateEncoder encoder = new HTTPRedirectDeflateEncoder();
encoder.setMessageContext(context);
encoder.setHttpServletResponse(httpServletResponse);
try {
encoder.initialize();
} catch (ComponentInitializationException e) {
throw new RuntimeException(e);
}
logger.info("Redirecting to receiver with AuthnRequest");
try {
encoder.encode();
} catch (MessageEncodingException e) {
throw new RuntimeException(e);
}
}
Related
First, I'm newbie at rest services. I'm trying to call a rest api with Kerberos Auth. There are 2 nodes at the server side. One is active and other one is in standby. When I set active node url as end point, I can perfectly call WS. But servers sometimes can redirect to other node. So I must set .setAutoRedirect() to true.
But when I do this, I got "Error 401 Authentication required" error.
How can I solve this problem? Thank you for your response.
public class KerberosAuth {
public KerberosAuth(){
}
public WebClient getWClient(URI end_point) {
WebClient wc = WebClient.create(end_point);
KerberosAuthOutInterceptor kbInterceptor = new KerberosAuthOutInterceptor();
AuthorizationPolicy policy = new AuthorizationPolicy();
policy.setAuthorizationType(HttpAuthHeader.AUTH_TYPE_NEGOTIATE);
policy.setAuthorization("KerberosClientKeyTab");
kbInterceptor.setPolicy(policy);
WebClient.getConfig(wc).getOutInterceptors().add(kbInterceptor);
//This line causes problem
WebClient.getConfig(wc).getHttpConduit().getClient()
.setAutoRedirect(true);
return wc;
}
}
private YarnWrapper getYarnWrapper() {
KerberosAuth ka = new KerberosAuth();
WebClient wc = ka.getWClient(end_point);
Response res = wc
.accept(MediaType.APPLICATION_JSON_TYPE)
//.acceptEncoding("gzip")
//.acceptLanguage("en-US")
.header("User-Agent", "Mozilla/5.0")
.get();
YarnWrapper yw = null;
try {
JsonParser parser = factory.createJsonParser((InputStream) res.getEntity());
yw = parser.readValueAs(YarnWrapper.class);
} catch (IOException e) {
e.printStackTrace();
}
return yw;
}
I am trying to fetch google contacts for a user via oAuth2 mechanism. I am following this tutorial - https://developers.google.com/identity/sign-in/web/server-side-flow
I have javascript code that calls start() on pageload -
function start() {
gapi.load('auth2', function() {
auth2 = gapi.auth2.init({
client_id: 'SOME_CLEINT_ID',
scope: 'https://www.googleapis.com/auth/contacts.readonly'
});
});
}
and
auth2.grantOfflineAccess().then(signInCallback);
and then -
function signInCallback(authResult) {
if (authResult['code']) {
var callback = function(data){
data = JSON.parse(data);
console.log(data);
};
callAjax({action: 'saveGmailAuth', gaccesscode: authResult['code']}, callback, true);
} else {
// There was an error.
}
}
This front end code calls my backend Java web servlet, which tries to get access token -
String authCode = request.getParameter("gaccesscode");
String REDIRECT_URI = "";
String CLIENT_SECRET_FILE = "G:/eclipse_proj/GoogleContacts/CLIENT_JSON_FILE.json";
GoogleClientSecrets clientSecrets;
try {
clientSecrets = GoogleClientSecrets.load(JacksonFactory.getDefaultInstance(),
new FileReader(CLIENT_SECRET_FILE));
REDIRECT_URI = clientSecrets.getDetails().getRedirectUris().get(0);
GoogleAuthorizationCodeTokenRequest tokenRequest = new GoogleAuthorizationCodeTokenRequest(new NetHttpTransport(),
JacksonFactory.getDefaultInstance(), "https://www.googleapis.com/oauth2/v3/token",
clientSecrets.getDetails().getClientId(), clientSecrets.getDetails().getClientSecret(), authCode,
REDIRECT_URI);
GoogleTokenResponse tokenResponse = tokenRequest.execute();
String accessToken = tokenResponse.getAccessToken();
GoogleCredential credential = new GoogleCredential().setAccessToken(accessToken);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Every time I try this java code, every time it gives me error at tokenRequest.execute() -
com.google.api.client.auth.oauth2.TokenResponseException: 400 Bad Request
{
"error" : "redirect_uri_mismatch",
"error_description" : "Bad Request"
}
With REDIRECT_URI as empty string, it give another error saying - redirect_uri_not_provided.
I tried it with both "https://www.googleapis.com/oauth2/v3/token" and "https://www.googleapis.com/oauth2/v4/token"
I need help figuring this out. What am I doing wrong here?
My redirect URI is - http://localhost:8080/GoogleContacts/Callback in both json file and in developer console for oauth2.
For redirect_uri in using Google APIs,go to your Google Dev console and type what you see as is:
//you can use any port you want
http:localhost:8080/oauth2callback
oauth2callback is the key ingredient.
I want to develop a SOAP client using CXF to connect to SharePoint. The authentication scheme is NTLM.
I am blocked on a scenario where the logged-in user of a machine (on which the SOAP client is being run) has access to SharePoint. The CXF soap client always uses the logged-in user. I want to specify some other user credentials (not the logged-in).
As CXF uses in-JDK HttpURLConnection; and what I have read about HttpURLConnection is, it bypasses the specified credentials when the logged-in user is NTLM authenticated.
Codes were tried on CXF version 2.7.11.
Solutions that I have tried out:
1) Setting Conduit authorization
String username = "user";
String password = "password";
JaxWsProxyfactoryBean factory1 = new JaxWsProxyfactoryBean();
factory1.setServiceClass(WebsSoap.class);
factory1.setAddress(url);
factory1.setUsername(username);
factory1.setPassword(password);
WebsSoap service = (WebsSoap) factory1.create();
Client client = ClientProxy.getClient(service);
HTTPconduit conduit = (HTTPconduit) client.getconduit();
conduit.getAuthorization().setAuthorizationType("NTLM");
conduit.getAuthorization().setUserName(username);
conduit.getAuthorization().setPassword(password);
HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
httpClientPolicy.setConnectionTimeout(36000);
httpClientPolicy.setAllowChunking(false);
conduit.setClient(httpClientPolicy);
service.getWeb(".");
Problem:
This does not work for the scenario specified above, as it always uses the logged-in credentials. And when I specify invalid credentials, it does not fail.
2) AsyncHTTPConduit
Another solution is to use AsyncHTTPConduit that uses HttpAsyncClient instead of HttpURLConnection. This is beacuse HTTP components do not bypass specified credentials and logged-in user can be ignored (I have successfully verified this with a test client using HttpClient).
Below is the code snippet::
Bus bus = BusFactory.getDefaultBus();
bus.setProperty( "use.async.http.conduit", "true" );
Client client = ClientProxy.getClient( service );
HTTPConduit http = (HTTPConduit)client.getConduit();
if ( http instanceof AsyncHTTPConduit ) {
AsyncHTTPConduit conduit = (AsyncHTTPConduit)http;
DefaultHttpAsyncClient defaultHttpAsyncClient;
try {
defaultHttpAsyncClient = conduit.getHttpAsyncClient();
}
catch ( IOException exception ) {
throw new RuntimeException( exception );
}
defaultHttpAsyncClient.getCredentialsProvider().setCredentials( AuthScope.ANY,
new NTCredentials( "username", "password", "", "domain" ) );
conduit.getClient().setAllowChunking( false );
conduit.getClient().setAutoRedirect( true );
}
Problem:
Above code throws error:
Authorization loop detected on conduit.
The above code snapshot shows the usage of DefaultHttpAsyncClient which is deprecated now and CloseableHttpAsyncClient is to be used instead. But CloseableHttpAsyncClient does not provide a way to specify credentials to an already existing CloseableHttpAsyncClient object. Not sure how to use CloseableHttpAsyncClient in this scenario.
3) Other solutions
The other solution that I tried out is to use sun.net.www.protocol.http.ntlm.NTLMAuthenticationCallback, to bypass logged-in user authentication, as mentioned here. Use this approach along with solution #1 mentioned above. This works as expected for valid/invalid credentials, and the code bypasses the logged-in credentials :). But when I specify invalid credentials, I do not get HTTP 401 error, instead I get
Could not send message, server reached max retries 20
I am trying to avoid this solution because it uses java’s internal package and there is no way to determine HTTP 401 error directly.
What can I do to arrive at a complete solution?
Try this interceptor. This will avoid automatic authentication.
public class DisableAutomaticNTLMAuthOutInterceptor extends AbstractPhaseInterceptor<Message>
{
private boolean isFieldsAvailable;
private Field tryTransparentNTLMProxyField;
private Field tryTransparentNTLMServerField;
public DisableAutomaticNTLMAuthOutInterceptor() {
super(Phase.PRE_STREAM);
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Void run() {
try {
DisableAutomaticNTLMAuthOutInterceptor.this.tryTransparentNTLMServerField = HttpURLConnection.class.getDeclaredField("tryTransparentNTLMServer");
DisableAutomaticNTLMAuthOutInterceptor.this.tryTransparentNTLMServerField.setAccessible(true);
DisableAutomaticNTLMAuthOutInterceptor.this.tryTransparentNTLMProxyField = HttpURLConnection.class.getDeclaredField("tryTransparentNTLMProxy");
DisableAutomaticNTLMAuthOutInterceptor.this.tryTransparentNTLMProxyField.setAccessible(true);
DisableAutomaticNTLMAuthOutInterceptor.this.isFieldsAvailable = true;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
});
}
#Override
public void handleMessage(final Message message) throws Fault {
if (this.isFieldsAvailable)
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Void run() {
try {
Object httpConnection = message.get("http.connection");
if (httpConnection != null) {
DisableAutomaticNTLMAuthOutInterceptor.this.processHttpConnection(message.get("http.connection"));
}
} catch (Throwable t) {
t.printStackTrace();
}
return null;
}
});
}
private void processHttpConnection(Object httpConnection) throws IllegalArgumentException, IllegalAccessException {
if (HttpURLConnection.class.isAssignableFrom(httpConnection.getClass())) {
tryTransparentNTLMServerField.set(httpConnection, Boolean.FALSE);
tryTransparentNTLMProxyField.set(httpConnection, Boolean.FALSE);
} else {
Field tempField = null;
for (Field field : httpConnection.getClass().getDeclaredFields()) {
if (HttpURLConnection.class.isAssignableFrom(field.getType())) {
field.setAccessible(true);
tempField = field;
break;
}
}
if (tempField != null) {
processHttpConnection(tempField.get(httpConnection));
}
}
}
}
I'm facing an issue in socialAuth java library. I used that library for logging to my app by using social networks. Login with Facebook is working properly. But when i try to use google and yahoo is does not work for me. Error occur when after authentication process, redirection part is not working properly,
#SuppressWarnings("unused")
#RequestMapping(params = "code")
private String oauth2Callback(final HttpServletRequest request,
HttpServletResponse response,
Model model) throws Exception {
String serviceReturnUrl = request.getParameter("service");
String clientAppKey = request.getParameter("app_key");
org.brickred.socialauth.AuthProvider provider = null;
SocialAuthManager manager = socialAuthTemplate.getSocialAuthManager();
if (manager != null) {
try {
provider = manager.connect(SocialAuthUtil.getRequestParametersMap(request));
} catch (Exception e) {
e.printStackTrace();
}
} else {
response.sendRedirect(appLoadConfigurer.getProperty("caslk"));
return "";
}
When redirecting Facebook to my app this method catch the request. but when it comes to google, i could not catch the request from google by using this method. request is not comes to here. Any one can idea to fix my issue as soon as possible
For google you will have to use
#RequestMapping(params = "openid.claimed_id")
Because google doen't return any attribute with name 'code' that's why it is not matching with this.
I am trying to create a simple app on the app engine where users log
in through their Google account, and then it adds an event to their
calendar.
And I am using Java along with Eclipse for this. I have found a simple
code online:
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// Create an instance of GoogleOAuthParameters
GoogleOAuthParameters oauthParameters = new GoogleOAuthParameters();
oauthParameters.setOAuthConsumerKey(CONSUMER_KEY);
oauthParameters.setOAuthConsumerSecret(CONSUMER_SECRET);
oauthParameters.setScope("http://docs.google.com/feeds/");
GoogleOAuthHelper oauthHelper = new GoogleOAuthHelper(
new OAuthHmacSha1Signer());
// Remember the token secret that we stashed? Let's get it back
// now. We need to add it to oauthParameters
String oauthTokenSecret = (String) req.getSession().getAttribute(
"oauthTokenSecret");
oauthParameters.setOAuthTokenSecret(oauthTokenSecret);
// The query string should contain the oauth token, so we can just
// pass the query string to our helper object to correctly
// parse and add the parameters to our instance of oauthParameters
oauthHelper.getOAuthParametersFromCallback(req.getQueryString(),
oauthParameters);
try {
// Now that we have all the OAuth parameters we need, we can
// generate an access token and access token secret. These
// are the values we want to keep around, as they are
// valid for all API calls in the future until a user revokes
// our access.
String accessToken = oauthHelper.getAccessToken(oauthParameters);
String accessTokenSecret = oauthParameters.getOAuthTokenSecret();
// In a real application, we want to redirect the user to a new
// servlet that makes API calls. For the safe of clarity and simplicity,
// we'll just reuse this servlet for making API calls.
oauthParameters = new GoogleOAuthParameters();
oauthParameters.setOAuthConsumerKey(CONSUMER_KEY);
oauthParameters.setOAuthConsumerSecret(CONSUMER_SECRET);
// This is interesting: we set the OAuth token and the token secret
// to the values extracted by oauthHelper earlier. These values are
// already in scope in this example code, but they can be populated
// from reading from the datastore or some other persistence mechanism.
oauthParameters.setOAuthToken(accessToken);
oauthParameters.setOAuthTokenSecret(accessTokenSecret);
oauthParameters.setOAuthCallback("http://www.facebook.com");
oauthHelper.getUnauthorizedRequestToken(oauthParameters);
// Create an instance of the DocsService to make API calls
DocsService client = new DocsService("Malware Inc.");
// Use our newly built oauthParameters
client.setOAuthCredentials(oauthParameters, new OAuthHmacSha1Signer());
URL feedUrl = new URL("https://docs.google.com/feeds/default/private/full");
DocumentListFeed resultFeed = client.getFeed(feedUrl,
DocumentListFeed.class);
for (DocumentListEntry entry : resultFeed.getEntries()) {
resp.getWriter().println(entry.getTitle().getPlainText());
}
} catch (OAuthException e) {
// Something went wrong. Usually, you'll end up here if we have invalid
// oauth tokens
resp.getWriter().println("Here is the problem");
//Server shows 500 problem
} catch (ServiceException e) {
// Handle this exception
}
}
I have registered my application and added the KEY and Secret above
the function, but when I deploy it to the app engine it gives a 500
server error.
Could someone post a simple java program that uses gdata and oauth to
log in a Google user and print the contacts on the screen?
Thanks.
-Manoj
I was facing the same problem, and it took me a while to figure it out.
Actually, the problem is that your are missing some parts in the OAuth authorization process.
As you may know, it a 3-legged process:
Get an unauthorized request token
Authorize the request token
Exchange the authorized request token for an access token and make calls to Google Data with it.
In your case, you are doing step 3 directly.
So before you can call the servlet you described above, and effectively retrieve user's Google Data,
the user must have grant access to your application, by browsing to an authorization URL from his web browser.
You need a first servlet , for example accessible at http://yourapp.com/RequestAccess
public void doGet(HttpServletRequest req, HttpServletResponse resp) {
GoogleOAuthParameters oauthParameters = new GoogleOAuthParameters();
oauthParameters.setOAuthConsumerKey(YOUR_CONSUMER_KEY);
oauthParameters.setOAuthConsumerSecret(YOUR_CONSUMER_SECRET);
OAuthHmacSha1Signer signer = new OAuthHmacSha1Signer();
GoogleOAuthHelper oauthHelper = new GoogleOAuthHelper(signer);
oauthParameters.setScope(FEED_SCOPE);
try {
oauthHelper.getUnauthorizedRequestToken(oauthParameters);
//GET THE UNAUTHORIZED TOKENS
String oauthRequestToken = oauthParameters.getOAuthToken();
String oauthTokenSecret = oauthParameters.getOAuthTokenSecret();
//SAVE THEM SOMEWEHERE (FOR EXAMPLE IN THE SESSION LIKE YOU DID)
// ....
//GET THE AUHTORIZATION URL
String authorizationURL= oauthHelper.createUserAuthorizationUrl(oauthParameters);
// YOU NOW HAVE THE AUHTORIZATION URL, SEND IT BACK TO THE USER SOMEHOW
// ( FOR EXAMPLE BY REDIRECTING THE REQUEST TO THAT URL)
// ...
} catch (OAuthException e1) {
LOGGER.error("error while getting unauthorized request token '{}' ", e1);
}
}
Once the user has navigate to that URL, and grant acces, you can now call your second servlet and it should work.
More info can be found on Google OAuth page here
Hope it helps!