Allow plugin users to connect to their personal servers via ssh keys

Allow plugin users to connect to their personal servers via ssh keys

by Lloyd D -
Number of replies: 33

Is there any way I could setup my plugin to allow user's to connect to their servers from their Moodle account (or their instance of the plugin) via an ssh key? Maybe the user could specify through user input fields in the plugin where their server is? Subsequently connecting via an ssh key?

Average of ratings: -
In reply to Lloyd D

Re: Allow plugin users to connect to their personal servers via ssh keys

by Mark Johnson -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

Hi Lloyd,

What exactly do you mean by "connect to their servers from their Moodle account"?  Can you give an example use case?

In reply to Mark Johnson

Re: Allow plugin users to connect to their personal servers via ssh keys

by Lloyd D -

Hi Mark, sorry for this slow reply. I've sort of managed to get what I wanted to work.. I created a keypair in the plugin and then displayed the public key under assignment settings for the user to copy over to their authorized_keys files on their server.. this then set up the connection between Moodle (my plugin) and their server. But the problem I have now is how can I only create this keypair once for each user? At the moment I have the keypair being created for each assignment the teacher creates... how can I only create the keypair once for each user? I don't want the teacher having to copy over a new public key over to their server each time they create a new assignment. Thanks, Lloyd.

In reply to Lloyd D

Re: Allow plugin users to connect to their personal servers via ssh keys

by Mark Johnson -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

Hi Lloyd,

It sounds like you need to store this keypair (perhaps using digest of each key as a unique ID rather than the full key) in a database table against the student's userid.  The plugin can then check if it's already generated a keypair and use the existing one instead of generating a new one.  That seems fairly straightforward though, so is there some complexity to the issue that I'm missing?

In reply to Mark Johnson

Re: Allow plugin users to connect to their personal servers via ssh keys

by Lloyd D -

Sorry Mark, I'm quite bad at explaining things sad what I meant is that the teacher will connect to their server under the assignment settings, where they can copy the public key over to their authorized_keys file on their server to establish the connection. So a bit like you said, I'd like the keypair to be generated only once for each teacher. So for each assignment the teacher will create, they would have the same private and public keys. How can I set this up that each user (teacher) using the plugin will only be given a keypair once?

In reply to Lloyd D

Re: Allow plugin users to connect to their personal servers via ssh keys

by Mark Johnson -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers
Ok, it sounds like you can do exactly what I suggested, but replacing "student" with "teacher".
In reply to Mark Johnson

Re: Allow plugin users to connect to their personal servers via ssh keys

by Lloyd D -

Ok that's great, but how would I set this up for each teacher that uses this plugin?

In reply to Lloyd D

Re: Allow plugin users to connect to their personal servers via ssh keys

by Mark Johnson -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers
Fairly straightforward logic: Where you currently generate the keypair, have a function instead which returns the keypair.  In the function, check in the database table if the keypair exists for the current user's ID.  If it does, return the existing keypair. If it doesn't, generate a new keypair, store it in the database against the teacher's user ID, and return the new keypair.
In reply to Mark Johnson

Re: Allow plugin users to connect to their personal servers via ssh keys

by Lloyd D -
Ok, so basically when the teacher makes a new assignment I'd have a function that checks to see if the keypair already exists in the mdl_user table? How can I check the record in the table that corresponds to the user (teacher) currently logged in? 
In reply to Lloyd D

Re: Allow plugin users to connect to their personal servers via ssh keys

by Mark Johnson -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

No, you'll want to create a new table that's part of your plugin, probably with the fields id, userid, publickey, privatekey (you might want to store a digest rather than the actual key).  You can get the current user's ID from the $USER global.

If you've not created new database tables in Moodle before, you'll want to read up on XMLDB and the Data definition API.

Average of ratings: Useful (1)
In reply to Mark Johnson

Re: Allow plugin users to connect to their personal servers via ssh keys

by Lloyd D -

Ah yes ok I see, I'll let you know how I get on. Thank you

In reply to Mark Johnson

Re: Allow plugin users to connect to their personal servers via ssh keys

by Lloyd D -

Hi Mark, I followed your advice and documentation you provided and I've successfully created the database table. I'm a bit confused to how I can search the table to see if a record with a specific userid already exists? This is the code I have at the moment but could you advise me on how to search the table and also if the record doesn't exist how I'd correctly insert a new record? I realise the code I have at the moment is practically pseudocode but does the if statement have potential to work like the way I have it now?

save settings function - checking if record exists or not


Or is this more accurate, using the record_exists function?

record_exists function to check whether record exists

In reply to Mark Johnson

Re: Allow plugin users to connect to their personal servers via ssh keys

by Lloyd D -

I seem to have done it! Thanks so much for your guidance. Would you mind checking what I have is correct?

Here is my get_settings function:

get_settings function retrieving ssh key

Have I setup the if statement correctly? Do i need to specify an else statement also? 


And here is my save_settings function:

save_settings function - saving keys only when not stored in the database table

What would I need to do if the record does exist? As you can see, at the moment I just have an echo statement but could I just if(exists == 0) ?

In reply to Lloyd D

Re: Allow plugin users to connect to their personal servers via ssh keys

by Mark Johnson -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

You can just do if ($exists) and if (!$exists) rather than using == 1 and == 0.

In fact, you could just stick the $DB->record_exists() call inside the if () condition to save creating a variable.

Unless there's something else you want to do when a keypair already exists in the save_settings, you don't need a branch for that.

In reply to Mark Johnson

Re: Allow plugin users to connect to their personal servers via ssh keys

by Lloyd D -

Ok thanks for that Mark. Can I ask you.. so after the keys are saved to the database and I try and establish a connection by retrieving the private key from the new table I created like so:

connecting to remote server

How can I make sure I retrieve the userid of the teacher that created the assignment and not the student currently logged in? At the moment I have it hardcoded to user 2.

In reply to Lloyd D

Re: Allow plugin users to connect to their personal servers via ssh keys

by Mark Johnson -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

That's a bit trickier as the user who created an assignment isn't already stored from what I can tell.

I'd suggest having a second event listener that listens for an event like core\event\course_module_created, and have another table where you store the id of the assignment against the id of the corresponding keypair from your first table, if the course module created is as assignment that you're interested in.

In reply to Mark Johnson

Re: Allow plugin users to connect to their personal servers via ssh keys

by Lloyd D -

Sorry Mark I'm quite confused by that. So there wouldn't be a way of doing something like assignment->get_teacher_id() ? Something along those lines....?

In reply to Lloyd D

Re: Allow plugin users to connect to their personal servers via ssh keys

by Mark Johnson -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

I had a quick look in the database and this doesn't seem to be stored anywhere.  Bear in mind that as far as Moodle's concerned, a "teacher" isn't really a thing, it's just a user who has a certain set of capabilities.  You could have several users who can edit a given assignment, and they could have different roles, so calling one the "teacher" for the assignment doesn't make a lot of sense in Moodle terms.

In reply to Mark Johnson

Re: Allow plugin users to connect to their personal servers via ssh keys

by Lloyd D -

Ah yeah you're right, I forgotten about that. Do you think there is a simpler way of achieving this rather than listening for an event etc? Is there a sufficient work around I could do?

In reply to Lloyd D

Re: Allow plugin users to connect to their personal servers via ssh keys

by Mark Johnson -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

I wouldn't have suggested you do the event listener if I knew of a simpler way smile

In reply to Mark Johnson

Re: Allow plugin users to connect to their personal servers via ssh keys

by Lloyd D -

Fair enough tongueout Can I ask how will the listening for the event course_module_created be useful? What I mean is how will it give information that will be used to find the user that created the assignment?

In reply to Lloyd D

Re: Allow plugin users to connect to their personal servers via ssh keys

by Mark Johnson -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

I'm assuming (I haven't checked) that the event will report the ID of the user who triggered it (i.e. the user who created the assignment), and the ID of the course module that was created.   You can then check that the course module is an instance of the assignment module, and do any other checks to make sure it's an assignment that's relevant to this case.

In reply to Mark Johnson

Re: Allow plugin users to connect to their personal servers via ssh keys

by Lloyd D -

Ok I see, so when then the event is triggered the ID of the user that created the assignment would be saved somewhere to be then used in my code that connects to the remote server? Wouldn't the event trigger before the student will make a submission? The event will trigger when the assignment is first created? So how will I be able to use the id in my code that connects to the server?


In reply to Lloyd D

Re: Allow plugin users to connect to their personal servers via ssh keys

by Mark Johnson -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

The course_module_created event will be triggered when the assignment (or any other module instance) is created, so you can store the assignment ID against the generated keypair at that point.  A different event would be triggered when a user submits an assignment. 


In reply to Mark Johnson

Re: Allow plugin users to connect to their personal servers via ssh keys

by Lloyd D -
Right ok that make sense, so this new table will contain a record of the assignmentID and the keypairid for the corresponding keypair in the other table? I would then get the userid through this foreign key, KeypairID. Would the tables look something like this:


Tables


In reply to Mark Johnson

Re: Allow plugin users to connect to their personal servers via ssh keys

by Lloyd D -

I've just thought of something too... would this event trigger and store details to the database regardless if my plugin was used or not? If the user saves an assignment which doesn't make use of my plugin, a record would be added to the table of the plugin? Would this be avoidable?

In reply to Lloyd D

Re: Allow plugin users to connect to their personal servers via ssh keys

by Mark Johnson -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

Those tables look right to me.  The moodle convention is to have the primary key field just called "id" rather than e.g. "keypairID", but I don't think that's a hard-and-fast requirement if you prefer not to.

In terms of your other question, if you can determine programmatically whether an assignment that's just been created makes use of your plugin, then you could do this in the event observer to decide whether to record the assignment ID.

One other possibility - in your save_settings function above, you should be able to do $this->assignment to get the assignment that your plugin is being used for. You could create the record in your assignment-keypair linking table with this assignment ID and a null keypair ID, then in your event observer you can check for the existence of the assignment ID in this table to know if it's using your plugin, and fill in the keypair ID if it is.

Average of ratings: Useful (1)
In reply to Mark Johnson

Re: Allow plugin users to connect to their personal servers via ssh keys

by Lloyd D -

Thanks for all the guidance you gave me, looks like I've done it smile although possibly in a slightly different way? Basically, when the user (teacher) saves their assignment I firstly save the keys and their userid to the keys table. Then immediately after I retrieve the id  (primary key) of the record in the keys table and insert it along with the current assignment ID to the linking table.. Then when the student submits their submission I retrieve the private key of the teacher from the keys table by performing this query:

retrieving the teacher's private key

Does this look correct to you? It seems to work anyway..?

Only thing is though.. when I delete an assignment the record in the linking table remains.. Is there any way I can enforce referential integrity? i.e. when the assignment is deleted the corresponding record in the linking table is also deleted? 

In reply to Lloyd D

Re: Allow plugin users to connect to their personal servers via ssh keys

by Mark Johnson -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

That seems to make sense.  I'm not sure about your second question, you'll have to look if there's some code in submission plugins that runs when the assignment they're linked to is deleted.

In reply to Mark Johnson

Re: Allow plugin users to connect to their personal servers via ssh keys

by Lloyd D -

Ok will do, thanks for that advice Mark. I wanted to ask you too, you said before that I should store a digest of the ssh keypair in the database? what did you mean by that? sorry my knowledge of these things is quite limited. I've read online that maybe I could protect the keys by enabling them to be only usable for certain IP addresses? i.e. if another host tries to connect then it would be denied as it's not on the list of the 'authorised' machines? I don't know if you have any experience on that?

In reply to Lloyd D

Re: Allow plugin users to connect to their personal servers via ssh keys

by Mark Johnson -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

What I meant was, assuming that you've got the key stored in a file on the filesystem, you might not want a duplicate of it in the database as that's another place for it to be compromised. However, you could store it's digest (a 1-way hash of the key, Google will tell you more if you're not familiar with this concept) in the database which would give you a unique identifier without storing the key itself.

In reply to Mark Johnson

Re: Allow plugin users to connect to their personal servers via ssh keys

by Lloyd D -

Ahh ok I see, I'm storing the key straight to the database so I guess that reduces the security risk.. I'll look into the hashing now smile

In reply to Lloyd D

Re: Allow plugin users to connect to their personal servers via ssh keys

by Visvanath Ratnaweera -
Picture of Particularly helpful Moodlers Picture of Translators
Hi

I understand your plan as: Students get assignments for which they need to login to a Unix computer through SSH. The question is how to distribute individual login credentials, which ideally should be the same as their Moodle login. Your Moodle uses its built-in authentication. Am I right?

IMHO the most sustainable solution is to use the same external authentication method https://docs.moodle.org/en/Category:Authentication for both. I know, it is too late for that.

Last time we needed the same thing, we found a very simple solution. The students have "pretty" registration numbers like dnnnnnn (d a letter, n all digits) and use them for login to Moodle. We created shell accounts with the same login and a easy password, which they had to change in their very first assignment. We could have generated a random password and made the script mail it the the student but spared the complications. It was a fast moving course, we just blocked the logins after a certain dead-line.
In reply to Visvanath Ratnaweera

Re: Allow plugin users to connect to their personal servers via ssh keys

by Lloyd D -

Hi Visvanath, thank you for your comment.  Could you see the reply I've given Mark, I've clarified what I meant in the question.