@@ -756,6 +756,8 @@ func (s *Server) handleToken(w http.ResponseWriter, r *http.Request) {
756756 s .handleAuthCode (w , r , client )
757757 case grantTypeRefreshToken :
758758 s .handleRefreshToken (w , r , client )
759+ case grantTypePassword :
760+ s .handlePasswordGrant (w , r , client )
759761 default :
760762 s .tokenErrHelper (w , errInvalidGrant , "" , http .StatusBadRequest )
761763 }
@@ -1150,6 +1152,221 @@ func (s *Server) handleUserInfo(w http.ResponseWriter, r *http.Request) {
11501152 w .Write (claims )
11511153}
11521154
1155+ func (s * Server ) handlePasswordGrant (w http.ResponseWriter , r * http.Request , client storage.Client ) {
1156+ // Parse the fields
1157+ if err := r .ParseForm (); err != nil {
1158+ s .tokenErrHelper (w , errInvalidRequest , "Couldn't parse data" , http .StatusBadRequest )
1159+ return
1160+ }
1161+ q := r .Form
1162+
1163+ nonce := q .Get ("nonce" )
1164+ // Some clients, like the old go-oidc, provide extra whitespace. Tolerate this.
1165+ scopes := strings .Fields (q .Get ("scope" ))
1166+
1167+ // Parse the scopes if they are passed
1168+ var (
1169+ unrecognized []string
1170+ invalidScopes []string
1171+ )
1172+ hasOpenIDScope := false
1173+ for _ , scope := range scopes {
1174+ switch scope {
1175+ case scopeOpenID :
1176+ hasOpenIDScope = true
1177+ case scopeOfflineAccess , scopeEmail , scopeProfile , scopeGroups , scopeFederatedID :
1178+ default :
1179+ peerID , ok := parseCrossClientScope (scope )
1180+ if ! ok {
1181+ unrecognized = append (unrecognized , scope )
1182+ continue
1183+ }
1184+
1185+ isTrusted , err := s .validateCrossClientTrust (client .ID , peerID )
1186+ if err != nil {
1187+ s .tokenErrHelper (w , errInvalidClient , fmt .Sprintf ("Error validating cross client trust %v." , err ), http .StatusBadRequest )
1188+ return
1189+ }
1190+ if ! isTrusted {
1191+ invalidScopes = append (invalidScopes , scope )
1192+ }
1193+ }
1194+ }
1195+ if ! hasOpenIDScope {
1196+ s .tokenErrHelper (w , errInvalidRequest , `Missing required scope(s) ["openid"].` , http .StatusBadRequest )
1197+ return
1198+ }
1199+ if len (unrecognized ) > 0 {
1200+ s .tokenErrHelper (w , errInvalidRequest , fmt .Sprintf ("Unrecognized scope(s) %q" , unrecognized ), http .StatusBadRequest )
1201+ return
1202+ }
1203+ if len (invalidScopes ) > 0 {
1204+ s .tokenErrHelper (w , errInvalidRequest , fmt .Sprintf ("Client can't request scope(s) %q" , invalidScopes ), http .StatusBadRequest )
1205+ return
1206+ }
1207+
1208+ // Which connector
1209+ connID := s .passwordConnector
1210+ conn , err := s .getConnector (connID )
1211+ if err != nil {
1212+ s .tokenErrHelper (w , errInvalidRequest , "Requested connector does not exist." , http .StatusBadRequest )
1213+ return
1214+ }
1215+
1216+ passwordConnector , ok := conn .Connector .(connector.PasswordConnector )
1217+ if ! ok {
1218+ s .tokenErrHelper (w , errInvalidRequest , "Requested password connector does not correct type." , http .StatusBadRequest )
1219+ return
1220+ }
1221+
1222+ // Login
1223+ username := q .Get ("username" )
1224+ password := q .Get ("password" )
1225+ identity , ok , err := passwordConnector .Login (r .Context (), parseScopes (scopes ), username , password )
1226+ if err != nil {
1227+ s .tokenErrHelper (w , errInvalidRequest , "Could not login user" , http .StatusBadRequest )
1228+ return
1229+ }
1230+ if ! ok {
1231+ s .tokenErrHelper (w , errAccessDenied , "Invalid username or password" , http .StatusUnauthorized )
1232+ return
1233+ }
1234+
1235+ // Build the claims to send the id token
1236+ claims := storage.Claims {
1237+ UserID : identity .UserID ,
1238+ Username : identity .Username ,
1239+ PreferredUsername : identity .PreferredUsername ,
1240+ Email : identity .Email ,
1241+ EmailVerified : identity .EmailVerified ,
1242+ Groups : identity .Groups ,
1243+ }
1244+
1245+ accessToken := storage .NewID ()
1246+ idToken , expiry , err := s .newIDToken (client .ID , claims , scopes , nonce , accessToken , connID )
1247+ if err != nil {
1248+ s .tokenErrHelper (w , errServerError , fmt .Sprintf ("failed to create ID token: %v" , err ), http .StatusInternalServerError )
1249+ return
1250+ }
1251+
1252+ reqRefresh := func () bool {
1253+ // Ensure the connector supports refresh tokens.
1254+ //
1255+ // Connectors like `saml` do not implement RefreshConnector.
1256+ _ , ok := conn .Connector .(connector.RefreshConnector )
1257+ if ! ok {
1258+ return false
1259+ }
1260+
1261+ for _ , scope := range scopes {
1262+ if scope == scopeOfflineAccess {
1263+ return true
1264+ }
1265+ }
1266+ return false
1267+ }()
1268+ var refreshToken string
1269+ if reqRefresh {
1270+ refresh := storage.RefreshToken {
1271+ ID : storage .NewID (),
1272+ Token : storage .NewID (),
1273+ ClientID : client .ID ,
1274+ ConnectorID : connID ,
1275+ Scopes : scopes ,
1276+ Claims : claims ,
1277+ Nonce : nonce ,
1278+ // ConnectorData: authCode.ConnectorData,
1279+ CreatedAt : s .now (),
1280+ LastUsed : s .now (),
1281+ }
1282+ token := & internal.RefreshToken {
1283+ RefreshId : refresh .ID ,
1284+ Token : refresh .Token ,
1285+ }
1286+ if refreshToken , err = internal .Marshal (token ); err != nil {
1287+ s .logger .Errorf ("failed to marshal refresh token: %v" , err )
1288+ s .tokenErrHelper (w , errServerError , "" , http .StatusInternalServerError )
1289+ return
1290+ }
1291+
1292+ if err := s .storage .CreateRefresh (refresh ); err != nil {
1293+ s .logger .Errorf ("failed to create refresh token: %v" , err )
1294+ s .tokenErrHelper (w , errServerError , "" , http .StatusInternalServerError )
1295+ return
1296+ }
1297+
1298+ // deleteToken determines if we need to delete the newly created refresh token
1299+ // due to a failure in updating/creating the OfflineSession object for the
1300+ // corresponding user.
1301+ var deleteToken bool
1302+ defer func () {
1303+ if deleteToken {
1304+ // Delete newly created refresh token from storage.
1305+ if err := s .storage .DeleteRefresh (refresh .ID ); err != nil {
1306+ s .logger .Errorf ("failed to delete refresh token: %v" , err )
1307+ s .tokenErrHelper (w , errServerError , "" , http .StatusInternalServerError )
1308+ return
1309+ }
1310+ }
1311+ }()
1312+
1313+ tokenRef := storage.RefreshTokenRef {
1314+ ID : refresh .ID ,
1315+ ClientID : refresh .ClientID ,
1316+ CreatedAt : refresh .CreatedAt ,
1317+ LastUsed : refresh .LastUsed ,
1318+ }
1319+
1320+ // Try to retrieve an existing OfflineSession object for the corresponding user.
1321+ if session , err := s .storage .GetOfflineSessions (refresh .Claims .UserID , refresh .ConnectorID ); err != nil {
1322+ if err != storage .ErrNotFound {
1323+ s .logger .Errorf ("failed to get offline session: %v" , err )
1324+ s .tokenErrHelper (w , errServerError , "" , http .StatusInternalServerError )
1325+ deleteToken = true
1326+ return
1327+ }
1328+ offlineSessions := storage.OfflineSessions {
1329+ UserID : refresh .Claims .UserID ,
1330+ ConnID : refresh .ConnectorID ,
1331+ Refresh : make (map [string ]* storage.RefreshTokenRef ),
1332+ }
1333+ offlineSessions .Refresh [tokenRef .ClientID ] = & tokenRef
1334+
1335+ // Create a new OfflineSession object for the user and add a reference object for
1336+ // the newly received refreshtoken.
1337+ if err := s .storage .CreateOfflineSessions (offlineSessions ); err != nil {
1338+ s .logger .Errorf ("failed to create offline session: %v" , err )
1339+ s .tokenErrHelper (w , errServerError , "" , http .StatusInternalServerError )
1340+ deleteToken = true
1341+ return
1342+ }
1343+ } else {
1344+ if oldTokenRef , ok := session .Refresh [tokenRef .ClientID ]; ok {
1345+ // Delete old refresh token from storage.
1346+ if err := s .storage .DeleteRefresh (oldTokenRef .ID ); err != nil {
1347+ s .logger .Errorf ("failed to delete refresh token: %v" , err )
1348+ s .tokenErrHelper (w , errServerError , "" , http .StatusInternalServerError )
1349+ deleteToken = true
1350+ return
1351+ }
1352+ }
1353+
1354+ // Update existing OfflineSession obj with new RefreshTokenRef.
1355+ if err := s .storage .UpdateOfflineSessions (session .UserID , session .ConnID , func (old storage.OfflineSessions ) (storage.OfflineSessions , error ) {
1356+ old .Refresh [tokenRef .ClientID ] = & tokenRef
1357+ return old , nil
1358+ }); err != nil {
1359+ s .logger .Errorf ("failed to update offline session: %v" , err )
1360+ s .tokenErrHelper (w , errServerError , "" , http .StatusInternalServerError )
1361+ deleteToken = true
1362+ return
1363+ }
1364+ }
1365+ }
1366+
1367+ s .writeAccessToken (w , idToken , accessToken , refreshToken , expiry )
1368+ }
1369+
11531370func (s * Server ) writeAccessToken (w http.ResponseWriter , idToken , accessToken , refreshToken string , expiry time.Time ) {
11541371 resp := struct {
11551372 AccessToken string `json:"access_token"`
0 commit comments