I'm trying to implement CAS into my login system, but I'm stuck on how to retrieve the "ticket". Basically, the ticket is returned in the URL as a parameter but I can't figure out how to parse it out.
Here is my attempted code:
login: function(req, res) {
if (req.session.authenticated) {
res.redirect('/dashboard');
} else {
var https = require('https');
var url = require('url');
var cas_url = 'https://auth-test.test.edu';
var login_service = '/cas/login';
var validation_service = '/cas/validate';
var service = 'https://localhost:1337';
res.redirect(cas_url + login_service + '?service=' + service);
console.log(req.headers);
}
}
After redirecting to my specified URL, the CAS server redirects back to (with sample ticket):
https://localhost:1337/?ticket=ST-10247-Qn0BuiSHob1dxcjODDku-cas-t1
Any ideas on how to optimize my code or retrieve the ticket somehow? Thanks!
EDIT:
For validation now, see comment below on selected answer:
index: function(req, res) {
var ticket = req.param('ticket');
if (req.session.authenticated) {
res.redirect('/dashboard');
} else if (ticket) {
var https = require('https');
var options = {
cas_url: 'https://auth-test.berkeley.edu',
login: '/cas/login',
validate: '/cas/validate',
service: 'http://localhost:1337'
};
// redirect to validate URL
res.redirect(options.cas_url + options.validate
+ '?service=' + options.service + '&ticket=' + ticket);
} else {
res.view({
title: 'Home'
});
}
}
If the validation passes through the body will have two lines:
yes
username
If the validation does not pass through, the HTML will only display one line:
no
How to I parse each line of the displayed HTML page?
You need to create an index route, point it to a controller action, and retrieve the token in that action. For example, in /config/routes.js, add:
'/': 'HomeController.index'
then in /api/controllers/HomeController:
index: function (req, res) {
// req.param will contain any route params, body params or
// query string params
var ticket = req.param('ticket');
return res.send("The ticket is: " + ticket);
}
https://localhost:1337/ will then point at that code, assuming you have SSL set up correctly on your server!
Related
I'm trying to do a post request onto my api, the api works perfectly ( I am able to post files, but not through a url), but now I'm trying to post through an url.
this is the code I have now, I removed some lines that aren't relevant to the question or were for testing.
request({
url: url + "gettoken"
, json: true
}, function (error, response, body) {
user = body;
var rs = fs.createReadStream(up.url);
var ws = request.post(url + "upload?token=" + `${user.token}&key=${user.key}&filename=${filename}`);
ws.on('drain', function () {
rs.resume();
});
rs.on('end', function () {
console.log(filename);
});
ws.on('error', function (err) {
console.error('cannot send file ' + err);
});
rs.pipe(ws);
})
Can anyone please help me.
So the idea is to upload a file that's located at up.url to another server at url + "upload?...".
Since fs.createReadStream is meant to read local files, and not URL's, you need something that can create a stream from a URL (or rather, retrieve that URL and stream the response).
You can also use request for that:
request({
url: url + "gettoken",
json: true
}, function (error, response, body) {
const user = body;
const rs = request.get(up.url);
const ws = request.post(url + "upload?token=" + `${user.token}&key=${user.key}&filename=${filename}`);
rs.on('end', function () {
console.log(filename);
});
ws.on('error', function (err) {
console.error('cannot send file ' + err);
});
rs.pipe(ws);
});
Typically, file uploads work through multipart/form-data, but your code doesn't suggest that being used here. If it is, the code would become something like this:
const ws = request.post(url + "upload?token=" + `${user.token}&key=${user.key}&filename=${filename}`, {
formData : {
the_file : rs
}
});
// no `rs.pipe(ws)`
I'm using localhost and have all the modules set up correctly and I've checked that the database exists. When I type in localhost:3000/pods/add?firstName='John' it's supposed to add it to the database, but for some reason it isn't working.
var express = require('express');
var _ = require('underscore');
var mongoose = require('mongoose');
var podStore = require('./lib/pod-handler.js');
var podsLibrary = require('./lib/pods-library.js');
var podList = [];
var mongoPort = 27017;
var app = express();
var port = 3000;
var router = express.Router();
var pods = podsLibrary.list();
mongoose.connect('mongodb://localhost:'+mongoPort+'/pods');
router.route('/').get(function(request, response) {
//console.log('You hit an empty URL .. :(');
response.status(503).send("Service Unavailable");
});
router.route('/lib').get(function(request, response) {
//console.log('You hit an empty URL .. :(');
response.status(200).send("Cool beans!");
});
router.route('/pods/list').get(function(request, response){
if(!pods){
return response.status(503).send("Service Unavailable");
}
return response.status(200).send(makeReadableList(pods));
function makeReadableList(pods){
var podsHtml = " ";
_.each(pods, function(value, key){podsHtml = podsHtml + key});
return podsHtml;
}
});
router.route('/pods/add').post(function(request, response){
if (!request.query){
return response.status(400).send("Please give first name");
}
var payload = request.query;
if (!payload.firstName){
return response.status(400).send("give name");
}
podStore.save({
firstName: payload.firstName,
lastName: payload.lastName
}, function(){
return response.status(200).send(payload.firstName + " has been added!");
var space = " ";
_.each(pods, function(value, key) {
key + space;
return space + payload.firstName + payload.secondName;
});
});
});
router.route('/pods').get(function(request, response) {
//console.log("We reached the POD page -- Yay! :D");
response.status(200).send("Server unavailable");
});
app.use('/', router);
app.listen(port, function () {
console.log('App listening on port %s', port);
});
I've checked over my code countless times and I can't seem to find the problem.
Here's the pod-handler file.
var PodDoc = require('../models/pods.js');
module.exports = {
save: save
}
function save(pod, callback){
var podToSave = new PodDoc();
podToSave.firstName = pod.firstName;
podToSave.lastName = pod.lastName;
/*podToSave.skills = pod.skills;
podToSave.avatarUrl = pod.avatarUrl;
podToSave.address = {
number: pod.address.number,
lineOne: pod.address.lineOne,
lineTwo: pod.address.lineTwo,
postcode: pod.address.postcode
}
podToSave.phoneNumbers = {
mobile: pod.phoneNumbers.mobile,
landline: pod.phoneNumbers.landline
}*/
podToSave.save(function(err){
if(err){
console.log(err);
} else {
console.log("Working");
callback();
}
})
}
When I type in localhost:3000/pods/add?firstName='John' it's supposed to add it to the database
If i understand correctly, you want to open this url in browser, and expect to have a record John in database.
Change router request type to GET, this
router.route('/pods/add').post(/*omitted*/);
to this
router.route('/pods/add').get(/*omitted*/);
Server is expecting POST request, but browser cannot handle it without FORM element or ajax request, browsers usually uses GET request, i mean when you open your url, it send GET request to server
There may be a typo error as in the url you are using port 300 where as the port configured for localhost is 3000.
When I type in localhost:300/pods/add?firstName='John'
I am creating a login application with node.js, I seem to have ran into a knowledge deficit in the area of transferring strings from the server to html.
I posted my current code at jsfiddle.
My application verifies the credentials to the mysql table then generates a basic token that contains the username password and the ip address of the user.
In the last block of code, where the client html posts to the server, I have two segments where you see send to basic user page and send to admin page.
I have attempted to research this subject, but i get nothing pertinent to the situation. can anyone guide me in the right direction on sending the user to the admin or user page while sending the token alongside of it?
As well, how can the express server send data to the client, for example
on the page, I want the database to hold pertinant information regarding the user, like address and phone number. How can this information be transmitted from the server to the client via html?
app.post('/', urlencodedParser, function (req, res) {
var date = new Date();
con.query("SELECT * from users WHERE username=" + con.escape(req.body.username) + " AND password=" + con.escape(req.body.password), function (err, rows, fields) {
if (err) {
console.log(err);
} else {
var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
if (rows == '' && rows == '') {
console.log('User Failed to login to the server with #'.red + con.escape(req.body.username) + ':' + con.escape(req.body.password));
res.sendFile(__dirname + '/admin/failure.html');
} else {
var isadmin = rows[0].admin;
var cryptomap = [req.body.username + ',' + req.body.password + ',' + ip];
var strcryptomap = cryptomap.toString(); // convert array to string
var token = encrypt(strcryptomap);
console.log(token + ' SENT'.red);
var backto = decrypt(token); //decr
var arr = backto.toString().split(","); // SPLITTING STRING TO SATISFY /VERIFY *************************************************
console.log(arr[0] + ' has valid token, encryption succsessful'.green);
con.query('UPDATE users SET crypto=' + con.escape(token) + 'WHERE username=' + con.escape(req.body.username), function (err, rows, fields) {
if (err) {
res.send(500);
} else {
console.log('Updated Crypto for ' + req.body.username);
if (isadmin == 0) {
// send to basic user page
res.send('USER');
} else {
//send to admin user page
res.sendto('http://google.com/?' + token);
}
}
});
}
}
});
});
To start, I'll answer the actual question you are asking.
The way I normally handle what you are trying to accomplish, is by using an ajax POST from the front end with the users credentials(https of course, never send credentials using http), have the server authenticate the user, create the token and respond to the ajax post with the token. From here, if the authentication was successful and the server responded with a token and whatever other information you wanted to get, you have a few options for storing it, I personally use cookies. After the token is stored, let the front end handle the redirect.
Having said all of that, I would definitely read up on authentication principles and the different ways your system can be attacked. I see a couple of red flags dealing with pretty basic authentication ideas/strategies.
Edit : Here is an example AJAX post to a login API endpoint that responds with a token and saves the username and token to cookies. Obviously your result data in the success function may be organized differently than mine but can be accessed in the same way. You can send whatever data you would like back in this result object and redirect accordingly
var loginData = {
username : $('#loginUsername').val(),
password : $('#loginPassword').val()
}
$.ajax({
type : "POST",
url : [your-endpoint-url],
data : loginData ,
success : function(result) {
setCookie('appUN', result.username);
setCookie('appTok', result.token);
location.href = '/dashboard';
},
error : function(result) {
location.href = '/login/Error';
}
});
function setCookie(cname, cvalue) {
var d = new Date();
d.setTime(d.getTime() + 10800000);
var expires = "expires="+d.toUTCString();
var path = "path=/";
document.cookie = cname + "=" + cvalue + "; " + expires + ";" + path;
}
To actually send the data back to the client from the server, in your API endpoint, you would do all of your logic to check the users credentials and if their credentials were valid, you could create a token and return something like
res.json({
username: username,
token: token
});
and this JSON object will be available in the success function as shown above.
If the users credentials were invalid, you could return something like
res.status(400).json({Message : "The username or password is incorrect"});
and because of the 400 status, it will be caught by the error function of your AJAX request
I have a node application that reads an uploaded file like so:
router.route('/moduleUpload')
.post(function (request, response) {
request.files.file.originalname = request.files.file.originalname.replace(/ +?/g, '');
var media = new Media(request.files.file, './user_resources/module/' + request.body.module_id + '/');
if (!fs.existsSync(media.targetDir)) {
fs.mkdirSync(media.targetDir, 0777, function (err) {
if (err) {
console.log(err);
response.send("ERROR! Can't make the directory! \n"); // echo the result back
}
});
fs.chmodSync(media.targetDir, 0777);
}
moveFile(media);
var token = jwt.encode({
mediaObject: media
}, require('../secret')());
response.status(200).json(token);
});
Now when this file is uploaded and status code 200 is recieved my system then calls the following route:
router.route('/resourcePath/:encodedString')
.all(function (req, res) {
var decoded = jwt.decode(req.params.encodedString, require('../secret')());
var mediaObject = decoded.mediaObject;
var ext = mediaObject.file.originalname.substr(mediaObject.file.originalname.lastIndexOf('.'));
var path = 'app_server' + mediaObject.targetDir.substring(1) + mediaObject.fileName + ext;
var fileExist = false;
res.status(200).send(path)
});
Now for some reason this call is being called before the file is correctly in place which results in that sometimes my users cannot see the content.
To make sure the file was in the folder i thought of the following code to add:
var fileExist = false;
while (!fileExist) {
if (fs.existsSync('/var/www/learningbankapp/'+path)) {
fileExist = true;
}
}
However im not sure that this a good solution namly because it goes against node.js nature. So my question is, is there a better way to do it?
So I keep Receiving an error when I'm trying to use OAuth with Asana's API. The error I'm receiving is "Error no route found". What am I doing wrong? I know that the request is most likely correct, but I believe it returns a hashed URL and i'm supposed to unhash it. This is sample code I am using from a Facebook OAuth though, so perhaps the code is incorrect and facebook api specific.
Here is my code:
$(function () {
checkHashLogin();
$('#signon').click(function () {
asanaLogin();
});
})
});
var appID = ****************;
function asanaLogin() {
var path = 'https://app.asana.com/-/oauth_authorize';
var queryParams = ['client_id=' + appID,
'redirect_uri=' + window.location,
'response_type=token'];
var query = queryParams.join('&');
var url = path + query;
window.location.replace(url);
}
function checkHashLogin() {
if (window.location.hash.length > 3) {
var hash = window.location.hash.substring(1);
if(hash.split('=')[0] == 'access_token')
{
var path = "https://app.asana.com/-/oauth_authorize";
var queryParams = [hash, 'callback=displayUser'];
var query = queryParams.join('&');
var url = path + query;
//use jsonp to call the graph
var script = document.createElement('script');
script.src = url;
document.body.appendChild(script);
}
}
}
function displayUser(user) {
setTimeout(function () { }, 1000);
if (user.id != null && user.id != "undefined") {
//Do Stuff
}
else {
alert('user error');
}
}
Here is a photo of my app credentials. My redirect location is just local because I am not hosting it on a server yet.
Looks like you're doing url = path + query when you might need to do url = path + "?" + query - the query string isn't separated, which means you end up requesting a path like https://app.asana.com/-/oauth_authorizeclientId=... which isn't recognized: hence, "no route found".
Hope that helps!