Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Impersonation Auth #1

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@mui/material": "^5.14.5",
"@types/bcrypt": "^5.0.0",
"@types/mongoose": "^5.11.97",
"@types/node": "20.5.1",
"@types/react": "18.2.20",
"@types/react-dom": "18.2.7",
"bcrypt": "^5.1.1",
"mongoose": "^7.4.4",
"mui": "^0.0.1",
"next": "13.4.19",
"next-auth": "^4.23.1",
"react": "18.2.0",
Expand Down
11 changes: 9 additions & 2 deletions src/lib/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@ import mongoose from "mongoose";

const adminSchema = new mongoose.Schema({
username: String,
password: String
password: String,
tokenId: String
});

export const Admin = mongoose.models.Admin || mongoose.model('Admin', adminSchema);
const userSchema = new mongoose.Schema({
username: String,
password: String
})

export const Admin = mongoose.models.Admin || mongoose.model('Admin', adminSchema);
export const User = mongoose.models.UserAuth || mongoose.model('UserAuth', userSchema);
2 changes: 1 addition & 1 deletion src/lib/dbConnect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ export async function ensureDbConnected() {
return;
}
alreadyDone = true;
await mongoose.connect(process.env.MONGO_URL, { useNewUrlParser: true, useUnifiedTopology: true, dbName: "courses" });
await mongoose.connect(process.env.MONGO_URL, { useNewUrlParser: true, useUnifiedTopology: true, dbName: "next-auth" });
}
160 changes: 142 additions & 18 deletions src/pages/api/auth/[...nextauth].ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import NextAuth from "next-auth"
import CredentialsProvider from "next-auth/providers/credentials"
import {Provider} from "next-auth/providers";
import { Provider } from "next-auth/providers";
import { ensureDbConnected } from '@/lib/dbConnect';
import { Admin } from "@/lib/db";
import { Admin, User } from "@/lib/db";
import bcrypt from 'bcrypt';

import GoogleProvider from "next-auth/providers/google"

import GoogleProvider from "next-auth/providers/google";
import GithubProvider from "next-auth/providers/github";

const saltRound = 10;

export const authOptions = {
// Configure one or more authentication providers
Expand All @@ -13,9 +18,84 @@ export const authOptions = {
clientId: process.env.NEXT_GOOGLE_CLIENT_ID,
clientSecret: process.env.NEXT_GOOGLE_CLIENT_SECRET,
}),
GithubProvider({
clientId: process.env.NEXT_GITHUB_CLIENT_ID,
clientSecret: process.env.NEXT_GITHUB_CLIENT_SECRET
}),
CredentialsProvider({
id: "credentials",
name: "Credentials",
id: "adminCredential",
name: "Admin",
type: "credentials",
credentials: {
username: { label: "Admin Username", type: "text", placeholder: "jsmith" },
password: { label: "Admin Password", type: "password" },
tokenId: { label: 'Admin Secret Token', type: 'text', placeholder: 'Only this if you are already a admin' }
},
// @ts-ignore
async authorize(credentials, req) {
await ensureDbConnected();

const username = credentials?.username || '';
const password = credentials?.password || '';
const tokenId = credentials?.tokenId || '';

if (tokenId.length > 0) {
const isAdmin = await Admin.findOne({ tokenId });
if (isAdmin) {
return {
id: isAdmin._id,
email: isAdmin.username
}
}
}
if (!tokenId) {
return null;
}
if (username.length > 0 && password.length > 0) {


const salt = await bcrypt.genSalt(saltRound);
const hashPassword = await bcrypt.hash(password, salt);

// Add logic here to look up the user from the credentials supplied
const admin = await Admin.findOne({ username });

if (!admin) {
const obj = { username: username, password: hashPassword, tokenId };
const newAdmin = new Admin(obj);
let adminDb = await newAdmin.save();
console.log(adminDb);
return {
id: adminDb._id,
email: adminDb.username,
}
} else {
//TODO:: Make this safer, encrypt passwords
const result = await bcrypt.compare(password, admin.password);
if (admin.tokenId.length == 0 && tokenId.length > 0) {
admin.tokenId = tokenId;
await admin.save();
}
if (!result) {
return null
}
// User is authenticated
return {
id: admin._id,
email: admin.username,
}
}
}




}
}),

CredentialsProvider({
id: "userCredentials",
name: "User",
type: "credentials",
credentials: {
username: { label: "Username", type: "text", placeholder: "jsmith" },
Expand All @@ -28,33 +108,77 @@ export const authOptions = {
}
const username = credentials.username;
const password = credentials.password;
// Add logic here to look up the user from the credentials supplied
const admin = await Admin.findOne({ username });
console.log(username)
console.log(password)
const salt = await bcrypt.genSalt(saltRound);
const hashPassword = await bcrypt.hash(password, salt);

if (!admin) {
const obj = { username: username, password: password };
const newAdmin = new Admin(obj);
let adminDb = await newAdmin.save();
console.log(adminDb);
// Add logic here to look up the user from the credentials supplied
const user = await User.findOne({ username });
console.log(user, 'from here')
if (!user) {
const obj = { username: username, password: hashPassword };
const newUser = new User(obj);
await newUser.save();
console.log(newUser);
return {
id: adminDb._id,
email: adminDb.username,
id: newUser._id,
email: newUser.username,
}
} else {
//TODO:: Make this safer, encrypt passwords
if (admin.password !== password) {
const result = await bcrypt.compare(password, user.password);
if (!result) {
return null
}
// User is authenticated
return {
id: admin._id,
email: admin.username,
id: user._id,
email: user.username,
}
}
}
}),

CredentialsProvider({
id: "Impersoncredentials",
name: "Imperson",
type: "credentials",
credentials: {
tokenId: { label: 'Admin Secret Token', type: 'text', placeholder: 'Only this if you are already a admin' },
imperson: { label: "Imperson's Username", type: 'text', placeholder: ':)' }
},
async authorize(credentials, req) {
await ensureDbConnected()
if (!credentials) {
return null;
}

const tokenId = credentials.tokenId;
const impersonUsername = credentials.imperson;

// Add logic here to look up the user from the credentials supplied
const admin = await Admin.findOne({ tokenId });

if (!admin) {
return null
}
//TODO:: Make this safer, encrypt passwords
const imperson = await User.findOne({ username: impersonUsername })
if(!imperson) {
return null;
}
console.log(imperson)
// User is authenticated
return {
id: imperson._id,
email: imperson.username,
}

}
})
] as Provider[],
secret: process.env.NEXTAUTH_SECRET,
secret: process.env.NEXT_AUTH_SECRET,
session: {
strategy: "jwt",
maxAge: 30 * 24 * 60 * 60, // 30 days
Expand Down
38 changes: 30 additions & 8 deletions src/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@

import { Inter } from 'next/font/google'
import { Button, Typography } from "@mui/material";
import {signIn, useSession, signOut} from "next-auth/react"
import { signIn, useSession, signOut } from "next-auth/react"
import { GetServerSidePropsContext } from 'next';
import { getServerSession } from 'next-auth';
import { authOptions } from './api/auth/[...nextauth]';


export default function Home() {
export default function Home({ }) {
const session = useSession();
console.error(session)
return (
<div style={{height: 60, background: "white", padding: 10}}>
{session.data && <div style={{display: "flex", justifyContent: "space-between"}}>
<Typography variant={"h4"} style={{color: "black"}}>
<div style={{ height: 60, background: "white", padding: 10 }}>
{session.data && <div style={{ display: "flex", justifyContent: "space-between" }}>
<Typography variant={"h4"} style={{ color: "black" }}>
{session.data.user?.email}
</Typography>
<div>
<Button variant={"contained"} onClick={() => signOut()}>Logout</Button>
</div>
</div>}
{!session.data && <div style={{display: "flex", justifyContent: "space-between"}}>
<Typography variant={"h4"} style={{color: "black"}}>
</div>}
{!session.data && <div style={{ display: "flex", justifyContent: "space-between" }}>
<Typography variant={"h4"} style={{ color: "black" }}>
Coursera
</Typography>
<div>
Expand All @@ -28,3 +31,22 @@ export default function Home() {
</div>
)
}

// export async function getServerSideProps(context) {
// const session = await getServerSession(context.req, context.res, authOptions)
// console.log(session);
// if (!session) {
// return {
// redirect: {
// destination: '/',
// permanent: false,
// },
// }
// }

// return {
// props: {
// session,
// },
// }
// }
2 changes: 1 addition & 1 deletion src/pages/ssr.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export default function Ssr({session}) {

export async function getServerSideProps(context) {
const session = await getServerSession(context.req, context.res, authOptions)

console.log(session)
if (!session) {
return {
redirect: {
Expand Down
Loading