How to authenticate a java web app with KeyRock? - fiware

We are trying to create a user authentication in our web app ( that we are developing in Java Spring MVC). For our authentication we want to use the token and user info acquired from the users fiware.lab account on global instance of keyrock.
Since Keyrock is based on OAuth2 protocol, what is the best approach to use keyrock from our web app?
Is there a java library that we could use for this purpose?
Is there a way to integrate spring security or apache oltu?
Every example would be more than welecome.
We only have the implementation of node.js but we need a java version of this:
var express = require('express');
var OAuth2 = require('./oauth2').OAuth2;
var config = require('./config');
// Express configuration
var app = express();
app.use(express.logger());
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.session({
secret: "skjghskdjfhbqigohqdiouk"
}));
app.configure(function () {
"use strict";
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
//app.use(express.logger());
app.use(express.static(__dirname + '/public'));
});
// Config data from config.js file
var client_id = config.client_id;
var client_secret = config.client_secret;
var idmURL = config.idmURL;
var response_type = config.response_type;
var callbackURL = config.callbackURL;
// Creates oauth library object with the config data
var oa = new OAuth2(client_id,
client_secret,
idmURL,
'/oauth2/authorize',
'/oauth2/token',
callbackURL);
// Handles requests to the main page
app.get('/', function(req, res){
// If auth_token is not stored in a session cookie it sends a button to redirect to IDM authentication portal
if(!req.session.access_token) {
res.send("Oauth2 IDM Demo.<br><br><button onclick='window.location.href=\"/auth\"'>Log in with FI-WARE Account</button>");
// If auth_token is stored in a session cookie it sends a button to get user info
} else {
res.send("Successfully authenticated. <br><br> Your oauth access_token: " +req.session.access_token + "<br><br><button onclick='window.location.href=\"/user_info\"'>Get my user info</button>");
}
});
// Handles requests from IDM with the access code
app.get('/login', function(req, res){
// Using the access code goes again to the IDM to obtain the access_token
oa.getOAuthAccessToken(req.query.code, function (e, results){
// Stores the access_token in a session cookie
req.session.access_token = results.access_token;
res.redirect('/');
});
});
// Redirection to IDM authentication portal
app.get('/auth', function(req, res){
var path = oa.getAuthorizeUrl(response_type);
res.redirect(path);
});
// Ask IDM for user info
app.get('/user_info', function(req, res){
var url = config.idmURL + '/user/';
// Using the access token asks the IDM for the user info
oa.get(url, req.session.access_token, function (e, response) {
var user = JSON.parse(response);
res.send("Welcome " + user.displayName + "<br> Your email address is " + user.email + "<br><br><button onclick='window.location.href=\"/logout\"'>Log out</button>");
});
});
// Handles logout requests to remove access_token from the session cookie
app.get('/logout', function(req, res){
req.session.access_token = undefined;
res.redirect('/');
});
console.log('Server listen in port 80. Connect to localhost');
app.listen(80);
Edit 1
Here is my set up:
and the end result error I get when I call the token:

Fiware devguide explains how this oauth2 flow works against KeyRock.
There also, you can find linked several oauth2 implementations like scribe-data, where you can find several examples on how to use oauth2 authentication against some of the most extended social networks.

Related

how to check if user id or conversation id or user alreadt exists in sunshine via node.js

I am auto replying a predefined welcome message to user when they are posting a message via fb page or WhatsApp. I want if user already exists in sunshine then not to reply to that user else reply them with welcome message. How can I check if user already exists?
'use strict';
// Imports
`enter code here`const express = require('express');
const bodyParser = require('body-parser');
const SunshineConversationsApi = require('sunshine-conversations-client');
var request = require('request')
// Config
let defaultClient = SunshineConversationsApi.ApiClient.instance;
let basicAuth = defaultClient.authentications['basicAuth'];
basicAuth.username = 'app_XXXXXXX';
basicAuth.password = 'XXXXXXXXXXXXXXXXX-bSwG85aM8qldJzTt4rgZlf_XQukWKE8ADMno85g';
const PORT = 5050;
const apiInstance = new SunshineConversationsApi.MessagesApi()
// Server https://expressjs.com/en/guide/routing.html
const app = express();
app.use(bodyParser.json());
// Expose /messages endpoint to capture webhooks
https://docs.smooch.io/rest/#operation/eventWebhooks
app.post('/messages', function(req, res) {
console.log('webhook PAYLOAD:\n',
JSON.stringify(req.body.events[0].payload.conversation.id, null, 4));
const appId = req.body.app.id;
const trigger = req.body.events[0].type;
// Call REST API to send message https://docs.smooch.io/rest/#operation/postMessage
if (trigger === 'conversation:message') {
const authorType = req.body.events[0].payload.message.author.type;
const displayName=req.body.events[0].payload.message.author.displayName;
if(authorType === 'user'){
const conversationId = req.body.events[0].payload.conversation.id;
console.log(conversationId);
console.log(displayName);
check_conversation_ID_with_sunshine(appId,conversationId);
//sendMessage(appId, conversationId);
res.end();
}
}
});
// Listen on port
app.listen(PORT, () => {
console.log(`App listening on port ${PORT}`);
});
async function sendMessage(appId, conversationId){
let messagePost = new SunshineConversationsApi.MessagePost();
messagePost.setAuthor({type: 'business'});
messagePost.setContent({type: 'text', text: 'Thanks boy'});
let response = await apiInstance.postMessage(appId, conversationId, messagePost);
//console.log('API RESPONSE:\n', response);
}
So [a simple] overall process could be:
User message comes in (including userId and conversationId)
fetch user's conversation
if len(response['messages']) == 1 (messages in the conversation)
send welcome message
(else no-op)
The caveat is that you could get false-negatives, if users send multiple messages, in quick succession, right at the beginning (instead of just one).
Some safe ways to do it would be to either:
look for the welcome message at the start of the convo (second message?)
i.e. iterate over [the first few] response['messages'], inspecting each one's text/metadata
when sending the welcome message, add a metadata flag on the conversation (e.g.: metadata.['welcomeSent']: True), searching for this flag for returning users
Doc references
Get a conversation's messages
doc page: https://docs.smooch.io/rest/#operation/listMessages
endpoint: https://api.smooch.io/v2/apps/{appId}/conversations/{conversationId}/messages
authentication: Basic, etc.
payload: <none>
response payload: {messages:[...], meta:{...}, links:{}}

Angular 4 with nodejs and Mysql connectivity

I am new in angular and node js. I want to know how angular connect with node js with mysql server. Which simple return query result. Can anyone help me.
Angular is a fronend framework and nodejs can be used to implement a backend for a system. And you can use mysql as your DBMS.
You have to implement your backend and frontend separately. From backend you are exposing endpoints, routes, apis to the external applications.
And you can access those apis,routes from angular using HttpClient module. You can make Http requests using that.
Hope this helps
You may need to use some libraries to make a connection between angular frontend and backend with MySQL database.
You will need the express.js to handle the backend for the data request. Because you use the MySQL database, the database language would be different from any others such as MongoDB. The express provided database integration for the different databases.
You also need a body-parser as a middleware to parse the request body. This is a very important part of your project. The req is very complicated and this middleware can help to get the information which you need.
Here is a sample of how to use express connect mysql.
var express = require('express');
var query = require('./query')
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var app = express();
//Middleware for bodyparsing using both json and urlencoding
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app.all('*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
});
//login
app.post('/login',(req,res)=>{
var opts = req.body;
query(" SELECT *FROM `v_users` WHERE userAcount = ?",opts.userName).then((result)=>{
var response = result[0];
if(opts.password !== response.u_password){
return res.send({
errorCode:'404',
errorMsg:'password error'
})
}
//loginToken
var loginToken = response.userAcount + Math.random()*Math.pow(10,16)
res.send({
loginToken:loginToken
})
})
})
var server = app.listen(3000,()=>{
console.log('success')
})
Here is the query method:
(function() {
var mysql = require('mysql');
// var session = require('cookie-session');
var query = (sql,key) => {
var connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'root123',
database: 'm_users'
});
connection.connect()
var promise = new Promise((resolve,reject)=>{
connection.query(sql,[key], function(error, results, fields) {
if(error){
reject(error)
}else{
resolve(results);
}
});
connection.end();
});
return promise;
}
module.exports = query;
})()

Ask for a password to show a page

I've made a very simple website with 1 page (main.html) just to put my Curriculum Vitae.
But to avoid all people seeing it I just want to ask for a password (i dont even need a username).
Is there a simple way to do this? It can be something like an alert asking for a password or something like that.
I'm trying this:
//Init App
const app = express();
//Auth
var preAuth = require('http-auth');
var basic = preAuth.basic({
realm: "Restricted Access. Please login to proceed."
}, function (username, password, callback) {
callback( (username === "user" && password === "password"));
}
);
app.use(preAuth.connect(basic));
//View Engine
app.set('views', path.join(__dirname, 'views'));
app.engine('html', engines.mustache);
app.set('view engine','html');
//Home route
app.get('/', function (req,res) {
res.render('main');
});
Please try it this way to see if it works correctly
// Authentication module.
var express = require('express');
var httpAuth = require('http-auth');
var authentication = httpAuth.basic({
realm: "Type your username and password."
}, (username, password, callback) => {
callback(username == 'root' && password.trim() == 'toor');
});
var app = express();
app.use(httpAuth.connect(authentication));
// Setup route.
app.get('/', (req, res) => {
res.send(`Hello from express - ${req.user}!`);
});
app.listen(3030);
The session data would be "root" (as a user) and "toor" (as a password).
Apparently the problem is the way you are using for the implementation of http-auth

Forge 3-Legged Oauth - Sign in as another User / Force logout

I got 3 legged to work, and I have my own session login/logout management.
After logout, if user wants to login again, and I send him to
https://developer.api.autodesk.com/authentication/v1/authorize, it's going straight to my callback with the previous user already authenticated instead of prompting for new login.
Seems like Autodesk is storing the session as a cookie so the only way to switch users after authorizing is to clear out the browser cache/data
Is there a way to force logout, or something similar to "Sign in as another user"?
This is my first time doing oauth, so I am not sure I am missing something, but seems like there should be way to force clear out the session and force a new login.
Edit
Let me further clarify what I am trying to achieve:
Here is what I have.
1. I direct the user to the authentication page directing it to:
https://developer.api.autodesk.com/authentication/v1/authorize?response_type=code&client_id=obQDn8P0GanGFQha4ngKKVWcxwyvFAGE&redirect_uri=http%3A%2F%2F{{mycallback}}%2Fcallback%3Ffoo%3Dbar&scope=data:read
The user logins in with his Autodesk credentials
The authorization flow redirect's the user to `mycallback.com/callback/?code={{code}}
My backend get's the code parameter from the url request, and makes a POST request to https://developer.api.autodesk.com/authentication/v1/gettoken
The request returns, among other things, an access_token
I store the access_token to the user's session, and use that to make the next requests to the API.
Up to this point, it works as I expect. Now I want to log the user out, and potentially sign in as a different user.
A /logout end point on my server clears the user session, eliminating the stored access_token.
Once the back end realized there is not active session/access_token, it redirect the user to the authentication flow (step #1 above).
At this point, I would expect to see another Autodesk login page, but instead, Autodesk's server automatically authorizes without a new login, and redirects user to call back, and the user logs in again.
So to rephrase my question, how do change the behavior on #9 above, so that the user has to re-enter his credential?
I am running into this often during development, where I login with my personal account, then I logout, and I would like to login with my work account.
Currently, the only way i can do that, is by Clearing my browser's cache.
That leads me to think Autodesk is storing the session in the browser, and that's why it's re-authenticating without getting new credentials.
The same behaviour happens on your dm.autodesk.io
After the first login, if i try to authorize again, I am not prompted for an login the 2nd time, instead it automatically re-logins in the first user I logged in with.
If I understand what's happening correctly, seems that the API should have an end-point that we can call when I user logs out to force a re-authentication.
Makes sense?
Thanks!
Just load this URL: "https://accounts.autodesk.com/Authentication/LogOut"
This will log out previous user session and a new user can logged in.
Refer this for more details: https://forge.autodesk.com/blog/log-out-forge
I'm not sure what you mean by "I send him to https://developer.api.autodesk.com/authentication/v1/authorize" but this has to happen on your server.
Check my sample at https://dm.autodesk.io: Allow popups and click the "User Data" in the navbar. Once you logged in, the user session is stored securely on the server. If you reload the page it will log you in automatically. If you click the navbar button again it will clear the session on the server and if you reload you will not be logged in. I guess that's the behaviour you are looking for.
The code for this project is located there. The 3-legged logic is handled from there and look as below (node.js):
import ServiceManager from '../services/SvcManager'
import { serverConfig as config } from 'c0nfig'
import { OAuth2 } from 'oauth'
import express from 'express'
module.exports = function() {
var router = express.Router()
///////////////////////////////////////////////////////////////////////////
// 2-legged client token: exposes a 'data:read' only token to client App
//
///////////////////////////////////////////////////////////////////////////
router.get('/token/2legged', async(req, res) => {
try {
var forgeSvc = ServiceManager.getService('ForgeSvc')
var token = await forgeSvc.request2LeggedToken('data:read')
res.json(token)
} catch (error) {
res.status(error.statusCode || 404)
res.json(error)
}
})
/////////////////////////////////////////////////////////////////////////////
// Initialize OAuth library
//
/////////////////////////////////////////////////////////////////////////////
var oauth2 = new OAuth2(
config.forge.oauth.clientId,
config.forge.oauth.clientSecret,
config.forge.oauth.baseUri,
config.forge.oauth.authorizationUri,
config.forge.oauth.accessTokenUri,
null)
/////////////////////////////////////////////////////////////////////////////
// login endpoint
//
/////////////////////////////////////////////////////////////////////////////
router.post('/login', function (req, res) {
var authURL = oauth2.getAuthorizeUrl({
redirect_uri: config.forge.oauth.redirectUri,
scope: config.forge.oauth.scope.join(' ')
})
res.json(authURL + '&response_type=code')
})
/////////////////////////////////////////////////////////////////////////////
// logout endpoint
//
/////////////////////////////////////////////////////////////////////////////
router.post('/logout', (req, res) => {
var forgeSvc = ServiceManager.getService(
'ForgeSvc')
forgeSvc.delete3LeggedToken(req.session)
res.json('success')
})
/////////////////////////////////////////////////////////////////////////////
// Reply looks as follow:
//
// access_token: "fk7dd21P4FAhJWl6MptumGkXIuei",
// refresh_token: "TSJpg3xSXxUEAtevo3lIPEmjQUxXbcqNT9AZHRKYM3",
// results: {
// token_type: "Bearer",
// expires_in: 86399,
// access_token: "fk7dd21P4FAhJWl6MptumGkXIuei"
// }
//
/////////////////////////////////////////////////////////////////////////////
router.get('/callback/oauth', (req, res) => {
var socketSvc = ServiceManager.getService(
'SocketSvc')
// filter out errors (access_denied, ...)
if (req.query && req.query.error) {
if (req.session.socketId) {
socketSvc.broadcast(
'callback', req.query.error,
req.session.socketId)
}
res.json(req.query.error)
return
}
if(!req.query || !req.query.code) {
res.status(401)
res.json('invalid request')
return
}
oauth2.getOAuthAccessToken(
req.query.code, {
grant_type: 'authorization_code',
redirect_uri: config.forge.oauth.redirectUri
},
function (err, access_token, refresh_token, results) {
try {
var forgeSvc = ServiceManager.getService(
'ForgeSvc')
var token = {
scope: config.forge.oauth.scope,
expires_in: results.expires_in,
refresh_token: refresh_token,
access_token: access_token
}
forgeSvc.set3LeggedTokenMaster(
req.session, token)
if(req.session.socketId) {
socketSvc.broadcast(
'callback',
'success',
req.session.socketId)
}
res.end('success')
} catch (ex) {
res.status(500)
res.end(ex)
}
}
)
})
/////////////////////////////////////////////////////////////////////////////
// logout route
//
/////////////////////////////////////////////////////////////////////////////
router.post('/logout', (req, res) => {
var forgeSvc = ServiceManager.getService(
'ForgeSvc')
forgeSvc.logout(req.session)
res.json('success')
})
///////////////////////////////////////////////////////////////////////////
// 3-legged client token: exposes a 'data:read' only token to client App
//
///////////////////////////////////////////////////////////////////////////
router.get('/token/3legged', async (req, res) => {
var forgeSvc = ServiceManager.getService(
'ForgeSvc')
try {
var token = await forgeSvc.get3LeggedTokenClient(
req.session)
res.json({
expires_in: forgeSvc.getExpiry(token),
access_token: token.access_token,
scope: token.scope
})
} catch (error) {
forgeSvc.logout(req.session)
res.status(error.statusCode || 404)
res.json(error)
}
})
return router
}

NodeJS sessions, cookies and mysql

I'm trying to build an auth system and I have app.js
var express = require('express')
, MemoryStore = require('express').session.MemoryStore
, app = express();
app.use(express.cookieParser());
app.use(express.session({ secret: 'keyboard cat', store: new MemoryStore({ reapInterval: 60000 * 10 })}));
app.use(app.router);
and the route.index as
var express = require('express')
, mysql = require('mysql')
, crypto = require('crypto')
, app = module.exports = express();
app.get('/*',function(req,res){
var url = req.url.split('/');
if (url[1] == 'favicon.ico')
return;
if (!req.session.user) {
if (url.length == 4 && url[1] == 'login') {
var connection = mysql.createConnection({
host : 'localhost',
user : 'user',
password : 'pass',
});
var result = null;
connection.connect();
connection.query('use database');
var word = url[3];
var password = crypto.createHash('md5').update(word).digest("hex");
connection.query('SELECT id,level FROM users WHERE email = "'+url[2]+'" AND password = "'+password+'"', function(err, rows, fields) {
if (err) throw err;
for (i in rows) {
result = rows[i].level;
}
req.session.user = result;
});
connection.end();
}
}
console.log(req.session.user)
when I access http://mydomain.com/login/user/pass a first time it shows in the last console call but a second time access the cookie is clean
Why do you not just use Express's session handling? if you use the express command line tool as express --sessions it will create the project template with session support. From there you can copy the session lines into your current project. There more information in How do sessions work in Express.js with Node.js? (which this looks like it may be a duplicate of)
As for sanitizing your SQL, you seem to be using the library, which will santitize your inputs for your if you use parameterized queries (ie, ? placeholders).
Final thing, you are using Express wrong (no offence). Express's router will let you split alot of your routes (along with allowing you to configure the favicon. See Unable to Change Favicon with Express.js (second answer).
Using the '/*' route will just catch all GET requests, which greatly limits what the router can do for you.
(continued from comments; putting it here for code blocks)
Now that you have an app with session support, try these two routes:
app.get('/makesession', function (req, res) {
req.session.message = 'Hello world';
res.end('Created session with message : Hello world');
});
app.get('/getsession', function (req, res) {
if (typeof req.session.message == 'undefined') {
res.end('No session');
} else {
res.end('Session message: '+req.session.message);
}
});
If you navigate in your browser to /makesession, it will set a session message and notify you that it did. Now if you navigate to /getsession, it will send you back the session message if it exists, or else it will tell you that the session does not exist.
You need to save your cookie value in the response object:
res.cookie('session', 'user', result);
http://expressjs.com/api.html#res.cookie